Compare commits

...

243 Commits
6.0.0 ... dev

Author SHA1 Message Date
Satyendra Hari
47643eb2d0 added docs 2023-07-24 19:39:44 +05:30
Satyendra Hari
7a5e502428 update the port 2023-07-24 18:06:46 +05:30
Satyendra Hari
47d4d3cff6 add to the container 2023-07-24 16:32:36 +05:30
Satyendra Hari
becce91a7c added new module 2023-07-24 16:31:13 +05:30
David Fowler
06d5164532
Remove envoy (#2127)
- Just go through the gateway directly
- We'll need to update the mobile version eventually
2023-06-16 10:40:57 -07:00
David Fowler
67d4c06b6d
Fixed the spa project (#2126)
- Clean up the SPA project (removed dead code)
- Fixed URLs in override file
2023-06-15 08:03:56 -07:00
David Fowler
508fa593d7
Added implict usings (#2125) 2023-06-15 05:25:36 -07:00
David Fowler
3b9560c26e
Clean up usings and controller attributes (#2124)
* Clean up usings and controller attributes
- Removed redundant attributes when the controllers already specifies what the result type is.
- Use StatusCodes instead of HttpStatusCode.
- Clean up namespaces and use type aliases to disambiguate the many DTOs defined.

* Forgot one

* Update src/Services/Webhooks/Webhooks.API/Controllers/WebhooksController.cs

Co-authored-by: Reuben Bond <203839+ReubenBond@users.noreply.github.com>

---------

Co-authored-by: Reuben Bond <203839+ReubenBond@users.noreply.github.com>
2023-06-14 20:56:52 -07:00
David Fowler
c7c2d1ca2f
Merge pull request #2123 from eerhardt/FixRedisBasketRepository
Cache JsonSerializerOptions
2023-06-13 13:52:36 -07:00
Eric Erhardt
5d13c097d3 Address PR feedback 2023-06-13 14:41:55 -05:00
Eric Erhardt
42e161d1f9 Use file scoped namespace. 2023-06-13 11:33:29 -05:00
Eric Erhardt
fd76f390ef Cache JsonSerializerOptions
According to https://github.com/dotnet/runtime/issues/65396, using a new JsonSerializerOptions every time JsonSerializer is invoked is a suboptimal pattern.

Fix this by caching JsonSerializerOptions instances.
2023-06-13 11:31:11 -05:00
Tarun Jain
3169a93344
Merge pull request #2107 from dotnet-architecture/davidfowl/common-services
Modernization
2023-05-16 22:54:58 +05:30
David Fowler
df4eb4c124 More code sharing and clean up WebHooks client 2023-05-09 07:05:40 -07:00
Reuben Bond
e4b94decb2 Use Services.Common in WebhookClient 2023-05-09 07:05:40 -07:00
Reuben Bond
6f4ae509f1 Port WebhookClient to WebApplicationBuilder 2023-05-09 07:05:40 -07:00
David Fowler
dbef61fdaf Nuke the cors from the mobile BFF 2023-05-09 07:05:40 -07:00
Reuben Bond
6ebde3fb5c Remove on-start health check in Ordering.BackgroundTasks so that it doesn't crash on startup 2023-05-09 07:05:39 -07:00
Reuben Bond
8f9f9d168f Add libman package to WebMVC to fix site 2023-05-09 07:05:39 -07:00
Reuben Bond
f5218e8087 Start adding connection strings for VS launch profile 2023-05-09 07:05:39 -07:00
Reuben Bond
72c8167ec0 Attempt to migrate Mobile BFF to common services pattern 2023-05-09 07:05:39 -07:00
Reuben Bond
8c9524c771 Reduce double writes in Application.FunctionalTests build 2023-05-09 07:05:39 -07:00
Reuben Bond
9c2b972cc9 Correctly set scopes for AuthorizeCheckOperationFilter 2023-05-09 07:05:39 -07:00
Reuben Bond
3858d7ccf7 Fix integration tests 2023-05-09 07:05:39 -07:00
David Fowler
a87efdef32 Small nit 2023-05-09 07:05:39 -07:00
Reuben Bond
52cdd1645a Fix Handler_sends_no_command_when_order_already_exists test 2023-05-09 07:05:39 -07:00
David Fowler
89a42e6c8f Removed session since its not used 2023-05-09 07:05:39 -07:00
David Fowler
d5533c0ff9 Move the pic controller to a minimal API 2023-05-09 07:05:39 -07:00
David Fowler
8debda5c67 Don't read the file into memory 2023-05-09 07:05:39 -07:00
David Fowler
6ad5e8fb09 Deleted test controller 2023-05-09 07:05:39 -07:00
David Fowler
bdebee70dc Clean up SignIn action 2023-05-09 07:05:39 -07:00
David Fowler
184ed15ef6 Clean up the auth delegating handler 2023-05-09 07:05:39 -07:00
David Fowler
af42aab95e Don't launch the browser for signalr 2023-05-09 07:05:39 -07:00
David Fowler
6933d9997d Forward SignalR requests through the web app 2023-05-09 07:05:39 -07:00
David Fowler
992b58d4bc Fixed cookies 2023-05-09 07:05:39 -07:00
David Fowler
a7cdb1df68 Remove unused code 2023-05-09 07:05:39 -07:00
David Fowler
0a07aea4ff Small refactoring of the helper methods 2023-05-09 07:05:38 -07:00
David Fowler
8c2ca8dbd9 Make WebMVC use the service common helpers 2023-05-09 07:05:38 -07:00
David Fowler
40315c69d7 Make docker use the reverse proxy 2023-05-09 07:05:38 -07:00
David Fowler
62a6f17595 Removed unneeded usings 2023-05-09 07:05:38 -07:00
David Fowler
64a2d69e92 Use YARP native config 2023-05-09 07:05:38 -07:00
David Fowler
69476a3175 Use the default YARP configuration 2023-05-09 07:05:38 -07:00
David Fowler
758d4bbe88 Specify routes in config 2023-05-09 07:05:38 -07:00
David Fowler
bd745121b2 Added comment about allowed origins 2023-05-09 07:05:38 -07:00
David Fowler
84c6b11c69 Remove cors from the signalr service
- The frontend hits the gateway which does the preflight request
2023-05-09 07:05:38 -07:00
David Fowler
561d48bc62 Fix cors and prefix rewriting 2023-05-09 07:05:38 -07:00
David Fowler
6a2fceb57c Fix more urls 2023-05-09 07:05:38 -07:00
David Fowler
c3efea0293 Add YARP to the BFF directly.
- This avoids the extra process hop
2023-05-09 07:05:38 -07:00
David Fowler
30ed0011cb Added YARP as an API gateway
- It will eventually replace envoy
2023-05-09 07:05:38 -07:00
David Fowler
06d74d1658 Small tweaks to make the MVC application run locally 2023-05-09 07:05:38 -07:00
David Fowler
50952bed10 Sort usings and delete web.config 2023-05-09 07:05:38 -07:00
David Fowler
f76a8c61db Make default URLs work 2023-05-09 07:05:38 -07:00
David Fowler
5a2d38575e Fixed identity url 2023-05-09 07:05:38 -07:00
David Fowler
670a9452e1 Remove health check 2023-05-09 07:05:38 -07:00
David Fowler
69b28c6add Added gRPC and HTTP endpoints via config 2023-05-09 07:05:38 -07:00
David Fowler
d0c710ebdc Docker compose works 2023-05-09 07:05:38 -07:00
David Fowler
e1ec790ddf Make more things work with docker compose 2023-05-09 07:05:38 -07:00
David Fowler
6b8992153a Rename extensions to extensions 2023-05-09 07:05:38 -07:00
David Fowler
d086d278e8 Moved repository to top level folder 2023-05-09 07:05:38 -07:00
David Fowler
3c00be38f9 Make BFF work and clean up ports 2023-05-09 07:05:37 -07:00
David Fowler
031996d87c Fixed check 2023-05-09 07:05:37 -07:00
David Fowler
5ea034106c Move extensions to Extensions folder 2023-05-09 07:05:37 -07:00
David Fowler
acd9a6d04b Clean up the identity project and make it use services common 2023-05-09 07:05:37 -07:00
David Fowler
7027967568 More random clean up 2023-05-09 07:05:37 -07:00
David Fowler
e166b28a0a Update the webhooks project to use service common 2023-05-09 07:05:37 -07:00
Reuben Bond
bcb1374d1e Avoid logging exception details twice in a given log, clean up 2023-05-09 07:05:37 -07:00
David Fowler
57d9baf106 Make the payment API use the common code 2023-05-09 07:05:37 -07:00
David Fowler
a37b0430b2 Remove unneeded dependencies 2023-05-09 07:05:37 -07:00
David Fowler
2a4a6abf9b Small tweaks
- Fix the payment profile's launch profile
- Added Services.Common to global usings
2023-05-09 07:05:37 -07:00
David Fowler
c41cd3830c Updated background tasks to use common service logic 2023-05-09 07:05:37 -07:00
David Fowler
0cb6b08300 Clean up the project 2023-05-09 07:05:37 -07:00
David Fowler
9743c83221 Use the common services in the Ordering.SignalRHub project 2023-05-09 07:05:37 -07:00
David Fowler
6e69a2472e Small naming tweaks for consistency 2023-05-09 07:05:37 -07:00
David Fowler
3357c70bc1 Clean up excess in project file 2023-05-09 07:05:37 -07:00
David Fowler
909f08675b Make the ordering API use the commmon services 2023-05-09 07:05:37 -07:00
David Fowler
a41560544c Split redis and health checks for redis 2023-05-09 07:05:37 -07:00
David Fowler
08e7c3424d Delete more cruft
- Remove migration from the tests
2023-05-09 07:05:37 -07:00
David Fowler
7681405eaf More clean up 2023-05-09 07:05:37 -07:00
David Fowler
ccaad9dc20 Removed unneeded project deps 2023-05-09 07:05:37 -07:00
Reuben Bond
cf02e90aad Migrate from ILoggerFactory to ILogger<T> and use Logging Source Generator 2023-05-09 07:05:37 -07:00
David Fowler
5397e8d5c8 Made small tweak to startup 2023-05-09 07:05:36 -07:00
David Fowler
0fd20ee962 More clean up
- Make the catalog API runnable
- Delete some cruft
2023-05-09 07:05:36 -07:00
David Fowler
34fc9496fd Small clean up to error handling code 2023-05-09 07:05:36 -07:00
David Fowler
a381a6923c Removed filters and special errors handling from MVC 2023-05-09 07:05:36 -07:00
David Fowler
3056418c92 Made a health check api 2023-05-09 07:05:36 -07:00
Reuben Bond
917764273b Remove superfluous UseDeveloperExceptionPage() and AddOptions() calls 2023-05-09 07:05:36 -07:00
Reuben Bond
e2d8590a26 Use WebApplicationBuilder in Mobile.Shopping.HttpAggregator 2023-05-09 07:05:36 -07:00
Reuben Bond
f8abb36bc6 Remove non-existent wwwroot from HttpAggregator projects 2023-05-09 07:05:36 -07:00
Reuben Bond
16b63001df Add Identity sections to config and consume (likely broken). Simplify integration tests 2023-05-09 07:05:36 -07:00
Reuben Bond
83200f9331 Fix Dockerfiles to include Services.Common 2023-05-09 07:05:36 -07:00
Reuben Bond
fea08c78bb Finish removing Autofac 2023-05-09 07:05:36 -07:00
Reuben Bond
b9f48faf99 Use simpler syntax for default 2023-05-09 07:05:36 -07:00
Reuben Bond
02c163246b Add EventBus connection string to Catalog.API 2023-05-09 07:05:36 -07:00
Reuben Bond
da024f9812 Remove Program.AppName 2023-05-09 07:05:36 -07:00
Reuben Bond
8da0a81514 Remove Serilog usage 2023-05-09 07:05:35 -07:00
Reuben Bond
5342c86af0 Remove Serilog from Identity.API and clean up 2023-05-09 07:05:35 -07:00
Reuben Bond
3f5f0b94ed Remove Program from Catalog.API 2023-05-09 07:05:35 -07:00
Reuben Bond
7d28625959 Remove Serilog from Web.Shopping.HttpAggregator 2023-05-09 07:05:35 -07:00
David Fowler
d96e4db08c Remove Program 2023-05-09 07:05:35 -07:00
David Fowler
c59e66861f - Add redis health check
- Add health checks on startup
2023-05-09 07:05:35 -07:00
David Fowler
56d47db91e Read from the connection strings section 2023-05-09 07:05:35 -07:00
David Fowler
b48ba7b74b More clean up 2023-05-09 07:05:35 -07:00
David Fowler
41056e54d8 Update grpc reference 2023-05-09 07:05:35 -07:00
David Fowler
45a04e4a6d Make services run individually and outside of docker
- Removed manual port binding code
- Disable Seq and logstash if config is null
- Disable serilog for now
- Remove IIS from some launch profiles
- Clean up some logging.
2023-05-09 07:05:35 -07:00
David Fowler
bff808016e Remove the UseVault and use the existance of the section 2023-05-09 07:05:35 -07:00
David Fowler
48f640088b More clean up 2023-05-09 07:05:35 -07:00
David Fowler
4e743ef666 Not needed 2023-05-09 07:05:35 -07:00
David Fowler
366019aaa3 Use the assembly name instead of the type name 2023-05-09 07:05:35 -07:00
David Fowler
d4319bdd47 Redirect to swagger 2023-05-09 07:05:35 -07:00
David Fowler
c565a8f799 Unify configuration 2023-05-09 07:05:35 -07:00
David Fowler
794c546d2e Fix the catalog tests 2023-05-09 07:05:35 -07:00
David Fowler
f46b03cb36 Use before Map 2023-05-09 07:05:35 -07:00
David Fowler
d1372cba64 First pass at making the catalog API use the common service helpers 2023-05-09 07:05:34 -07:00
David Fowler
7da7e98a55 Configure so tests work again 2023-05-09 07:05:34 -07:00
David Fowler
9d52426a49 Use default logger 2023-05-09 07:05:34 -07:00
David Fowler
57a93f63f0 More customization 2023-05-09 07:05:34 -07:00
David Fowler
8a40e9fb48 More schema 2023-05-09 07:05:34 -07:00
David Fowler
3fee612e68 More tweaks 2023-05-09 07:05:34 -07:00
David Fowler
00fc3d8a65 More defaults 2023-05-09 07:05:34 -07:00
David Fowler
9af6d6342d Initial attempt at making a common service configuration 2023-05-09 07:05:34 -07:00
David Fowler
e7e0eed9cc Fixed remaining tests
- Lots of duplication zomg
2023-05-09 07:05:34 -07:00
David Fowler
c7edd50b38 Fix ordering and basked scenarios 2023-05-09 07:05:34 -07:00
David Fowler
233b6e56c1 Fixed catalog functional tests 2023-05-09 07:05:34 -07:00
David Fowler
d4c2f17c36 Remove whitespace 2023-05-09 07:05:34 -07:00
David Fowler
746e5da7fa Make more tests pass 2023-05-09 07:05:34 -07:00
David Fowler
f3d2843166 Make tests work 2023-05-09 07:05:34 -07:00
Reuben Bond
91247ec52e BAD MISC - playing with tests 2023-05-09 07:05:34 -07:00
Reuben Bond
d62ebcb791 Fix IncludeScopes 2023-05-09 07:05:34 -07:00
Reuben Bond
109853983d Remove gRPC generated code from global usings etc 2023-05-09 07:05:34 -07:00
Reuben Bond
d91da03665 Fix IncludeScopes setting in appsettings.json for WebSPA 2023-05-09 07:05:34 -07:00
Reuben Bond
746363bfd3 Remove accidentally committed keys and update .gitignore to prevent them being added again 2023-05-09 07:05:34 -07:00
Tarun Jain
3ae0cefbcf
Merge pull request #2105 from ReubenBond/rebond/1
Fix brace placement
2023-05-08 14:40:50 +05:30
Reuben Bond
451d79f7b9 Fix formatting 2023-05-04 06:48:37 -07:00
Reuben Bond
9d38de0c83
Merge pull request #2092 from erjain/update/webshoppingagg-webap-builder
Update/webshoppingagg webapp builder
2023-04-27 12:35:12 -07:00
Tarun Jain
65e2f13ca2 Resolving conversation on PR 2023-04-28 00:43:58 +05:30
Tarun Jain
7e2a966dbf
Merge pull request #2088 from RikVanHaaren/dev
Fix spelling
2023-04-25 17:11:27 +05:30
Tarun Jain
24858e50b7 formatting program.cs 2023-04-25 01:54:48 +05:30
Tarun Jain
52fb849b84 WebShopping-Agg: migrate to WebApplicationBuilder 2023-04-25 01:53:28 +05:30
Tarun Jain
7d06508e22
Merge pull request #2089 from erjain/update/ordering-webappbuilder
Update/ordering webappbuilder
2023-04-25 01:49:28 +05:30
Tarun Jain
ce5a165dd0 add editorconfig at solution root node 2023-04-25 01:38:59 +05:30
Tarun Jain
9a707ecaa1 remove editorconfig.bak 2023-04-19 00:20:42 +05:30
Tarun Jain
9759596899 Commit to migrate Oredeing.BackkgroundTasks and SignalRHub to webAppBuilder 2023-04-19 00:19:52 +05:30
Tarun Jain
b9e585b2e4
Merge pull request #2085 from erjain/update/payment-api
Commit to migrate payment api to WebApplicationBuilder
2023-04-19 00:17:19 +05:30
Rik van Haaren
ff78bb7577
Fix spelling 2023-04-18 15:49:56 +02:00
Tarun Jain
212343f274 delete startup.cs 2023-04-17 22:45:12 +05:30
Tarun Jain
433419b583 update payment.csproj 2023-04-17 22:28:28 +05:30
Tarun Jain
c0cc12ad0c Commit to migrate payment api to WebApplicationBuilder 2023-04-12 23:32:11 +05:30
Tarun Jain
ee673d9180
Merge pull request #2079 from erjain/update/ordering-api-webAppBuilder
Migrate Ordering.API to WebApplicationBuilder
2023-04-12 22:23:57 +05:30
Tarun Jain
e1fc28be8b add .editorconfigfiles 2023-03-31 23:26:34 +05:30
Tarun Jain
fee79c40a4 Migrate Ordering.API to WebApplicationBuilder 2023-03-30 12:01:37 +05:30
Tarun Jain
c8f1e0f148
Merge pull request #2075 from erjain/update/basket-api-webAppBuilder
Basket.API: Commit to migrate to WebApplication Builder
2023-03-29 00:37:28 +05:30
Tarun Jain
bb4307478c Fix formatting 2023-03-28 22:10:42 +05:30
Tarun Jain
19217e0939 Basket.API: Commit to migrate to WebApplication Builder 2023-03-27 23:56:55 +05:30
Tarun Jain
4a86d5e93f
Merge pull request #2073 from erjain/update/catalog-api-webapplication-builder
Catalog.API: Commit to migrate catalog api to webapplication builder
2023-03-27 23:50:54 +05:30
Tarun Jain
d6ea0cbdf5 commit use use CreateAsyncScope 2023-03-27 23:48:14 +05:30
Tarun Jain
e9351bfb2c Catalog.API: Commit to migrate catalog api to webapplication builder 2023-03-24 15:18:06 +05:30
Tarun Jain
0740fd42b1
Merge pull request #2066 from dotnet-architecture/dependabot/npm_and_yarn/src/Web/WebSPA/Client/webpack-5.76.0
Bump webpack from 5.75.0 to 5.76.0 in /src/Web/WebSPA/Client
2023-03-15 00:10:17 +05:30
dependabot[bot]
88a9a49da4
Bump webpack from 5.75.0 to 5.76.0 in /src/Web/WebSPA/Client
Bumps [webpack](https://github.com/webpack/webpack) from 5.75.0 to 5.76.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.75.0...v5.76.0)

---
updated-dependencies:
- dependency-name: webpack
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-14 17:59:40 +00:00
Tarun Jain
390a37aca2
Merge pull request #2064 from erjain/update/eShop-refresh
Update and cleanup eShop
2023-03-14 23:28:27 +05:30
Reuben Bond
f92e02f3dd Convert WebStatus to WebApplicationBuilder 2023-03-10 13:47:18 +05:30
Reuben Bond
a0adc4bbf3 Remove unnecessary jQuery from WebStatus 2023-03-10 13:09:41 +05:30
Reuben Bond
98635a3e93 Eliminate Azure Dev Spaces 2023-03-10 13:09:35 +05:30
Reuben Bond
3097651747 Fix Docker build after moving to centralized packaging 2023-03-10 11:50:14 +05:30
Reuben Bond
10a783c5b4 NuGet: clear other sources 2023-03-10 11:49:56 +05:30
Reuben Bond
8552d3ada6 Do not publish or pack test projects 2023-03-10 11:49:24 +05:30
Reuben Bond
631a64940e Fix compiler warnings for unused variables 2023-03-10 11:49:01 +05:30
Reuben Bond
0cbd7b24e8 FIX: add Key Vault configuration 2023-03-10 11:48:21 +05:30
Reuben Bond
a2c45956a3 Use centralized package versioning 2023-03-10 11:45:18 +05:30
Reuben Bond
dbee1dad6d Add launchSettings.json 2023-03-10 01:14:51 +05:30
Reuben Bond
7a6e07cb64 WebMVC: Migrate to WebApplicationBuilder and delete Startup 2023-03-10 00:43:44 +05:30
Tarun Jain
242cbeabaf minor fix to removal of deprecated Azure Dev Spaces support 2023-03-10 00:39:19 +05:30
Reuben Bond
e43cf8effa Remove deprecated Azure Dev Spaces support 2023-03-09 23:35:11 +05:30
Reuben Bond
68d0df2e2f WebSPA: minor style fixes 2023-03-09 23:21:36 +05:30
Reuben Bond
77ea8ef352 Remove obsolete Azure Key Vault package 2023-03-09 23:18:46 +05:30
Reuben Bond
f7f4259147 Update JS libraries 2023-03-09 23:18:36 +05:30
Reuben Bond
049c4af196 WebSPA: migrate to WebApplicationBuilder and delete Startup 2023-03-09 22:26:46 +05:30
Reuben Bond
85ad916fcb Remove redundant using directives 2023-03-09 17:37:33 +05:30
Reuben Bond
b5d9d9653d Fix tests in Visual Studio by correcting connection strings 2023-03-09 17:36:11 +05:30
Reuben Bond
2c94c38269 Update NodeJS, NPM, and deps 2023-03-09 17:30:47 +05:30
Tarun Jain
faeebd3e2b
Merge pull request #2054 from erjain/fix/dependabot-alerts
migrate WebSPA to angular@15.x and fix vulnerability
2023-03-03 11:54:53 +05:30
James Montemagno
fed2b179eb
Merge pull request #2061 from erjain/fix/docs#19072
fixes docs issue #19072
2023-03-02 10:44:06 -08:00
Tarun Jain
4f58e58d46 fixes docs issue #19072 2023-03-02 18:40:56 +05:30
Tarun Jain
9c655ff9f0 commit to fix WebSPA build error 2023-02-25 16:58:51 +05:30
Tarun Jain
c0d58305b3 remove argument extract-css 2023-02-24 16:50:04 +05:30
Tarun Jain
2231774e70 fix Node_Image version 2023-02-24 16:45:21 +05:30
Tarun Jain
8bd43a4db4 Commit to update node version and npm version in Dockerfile docker-compose.yml 2023-02-24 16:29:29 +05:30
Tarun Jain
5ca9c997b7 commit to update vulnerable versions of minimist - Prototype Pollution in minimist 2023-02-24 15:20:06 +05:30
Tarun Jain
a04b214705 Commit to resolve minimatch ReDoS vulnerability 2023-02-24 15:13:05 +05:30
Tarun Jain
5ccbce36b5 commit to resolve vulnerable versions of @angular/core via node_modules/codelyzer 2023-02-24 13:34:46 +05:30
Tarun Jain
47f9559de0 Commit to migrate angular version to latest '15.x' 2023-02-23 16:20:31 +05:30
Tarun Jain
d9d0bd2302 commit to migrate angular version to '14.x' 2023-02-23 16:15:24 +05:30
Tarun Jain
0fd7b932fc commit to migrate angualr version to @angular 13.3.10 2023-02-23 16:01:05 +05:30
Tarun Jain
2a26c4be10 fixes with some package updates 2023-02-23 15:15:05 +05:30
Tarun Jain
042d6ce621 commit to migrate to 12.2.18 2023-02-23 13:17:19 +05:30
Tarun Jain
286971e60c
Merge pull request #2052 from sispehar/sispehar/fix/helm/configmap/trustservercertificate
adding TrustServerCertificate=true to ConnectionString in Helm templates
2023-02-20 19:45:10 +05:30
Simon
bb554c1706 adding TrustServerCertificate=True to ConnectionString in Helm templates 2023-02-17 20:51:53 +01:00
James Montemagno
7cf90e06fd
Merge pull request #2048 from erjain/fix/certificate-issue
commit to resolve RemoteCertificateValidationCallback issue
2023-02-14 09:00:48 -08:00
Tarun Jain
98e7e53636 commit to resolve RemoteCertificateValidationCallback issue 2023-02-10 11:46:13 +05:30
Tarun Jain
3e991acc50
Merge pull request #2019 from dotnet-architecture/dependabot/npm_and_yarn/src/Web/WebSPA/Client/express-4.18.2
Bump express from 4.17.2 to 4.18.2 in /src/Web/WebSPA/Client
2023-02-07 13:19:19 +05:30
Tarun Jain
fa9e955a2b
Merge pull request #2016 from dotnet-architecture/dependabot/npm_and_yarn/src/Web/WebSPA/Client/decode-uri-component-0.2.2
Bump decode-uri-component from 0.2.0 to 0.2.2 in /src/Web/WebSPA/Client
2023-02-06 18:36:42 +05:30
Tarun Jain
50d945a395
Merge pull request #2043 from dotnet-architecture/dependabot/npm_and_yarn/src/Web/WebSPA/Client/jszip-3.10.1
Bump jszip from 3.7.1 to 3.10.1 in /src/Web/WebSPA/Client
2023-02-06 18:34:49 +05:30
Tarun Jain
ea54e4482f
Merge pull request #2015 from dotnet-architecture/dependabot/npm_and_yarn/src/Web/WebSPA/Client/qs-6.5.3
Bump qs from 6.5.2 to 6.5.3 in /src/Web/WebSPA/Client
2023-02-06 18:31:56 +05:30
dependabot[bot]
e3715d0213
Bump qs from 6.5.2 to 6.5.3 in /src/Web/WebSPA/Client
Bumps [qs](https://github.com/ljharb/qs) from 6.5.2 to 6.5.3.
- [Release notes](https://github.com/ljharb/qs/releases)
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.5.2...v6.5.3)

---
updated-dependencies:
- dependency-name: qs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-06 12:51:58 +00:00
Tarun Jain
678c80cf98
Merge pull request #2029 from dotnet-architecture/dependabot/npm_and_yarn/src/Web/WebSPA/Client/json5-1.0.2
Bump json5 from 1.0.1 to 1.0.2 in /src/Web/WebSPA/Client
2023-02-06 18:20:27 +05:30
Tarun Jain
676d138962
Merge pull request #2039 from dotnet-architecture/dependabot/npm_and_yarn/src/Web/WebSPA/Client/ua-parser-js-0.7.33
Bump ua-parser-js from 0.7.31 to 0.7.33 in /src/Web/WebSPA/Client
2023-02-06 18:18:23 +05:30
Tarun Jain
dabdcac3bd
Merge pull request #2044 from dotnet-architecture/dependabot/npm_and_yarn/src/Web/WebSPA/Client/http-cache-semantics-4.1.1
Bump http-cache-semantics from 4.1.0 to 4.1.1 in /src/Web/WebSPA/Client
2023-02-06 18:11:15 +05:30
Tarun Jain
9a914889fd
Merge pull request #2045 from erjain/net7-duende-fix
update README.md
2023-02-06 17:49:59 +05:30
Tarun Jain
ad8c8054fe updated Contributing.md 2023-02-06 16:29:19 +05:30
Tarun Jain
4119fe06dc updates the branch-guide.md 2023-02-06 16:20:32 +05:30
Tarun Jain
368952d432 update README.md 2023-02-03 14:50:35 +05:30
dependabot[bot]
72cf029258
Bump http-cache-semantics from 4.1.0 to 4.1.1 in /src/Web/WebSPA/Client
Bumps [http-cache-semantics](https://github.com/kornelski/http-cache-semantics) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/kornelski/http-cache-semantics/releases)
- [Commits](https://github.com/kornelski/http-cache-semantics/compare/v4.1.0...v4.1.1)

---
updated-dependencies:
- dependency-name: http-cache-semantics
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-03 09:06:39 +00:00
Tarun Jain
e15a62270c
Merge pull request #2012 from erjain/net7-duende-fix
update to Net7 and Duende IdentityServer 6.2
2023-02-03 14:33:43 +05:30
dependabot[bot]
79c4d06747
Bump jszip from 3.7.1 to 3.10.1 in /src/Web/WebSPA/Client
Bumps [jszip](https://github.com/Stuk/jszip) from 3.7.1 to 3.10.1.
- [Release notes](https://github.com/Stuk/jszip/releases)
- [Changelog](https://github.com/Stuk/jszip/blob/main/CHANGES.md)
- [Commits](https://github.com/Stuk/jszip/compare/v3.7.1...v3.10.1)

---
updated-dependencies:
- dependency-name: jszip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-02 18:34:10 +00:00
dependabot[bot]
29241ec3d2
Bump ua-parser-js from 0.7.31 to 0.7.33 in /src/Web/WebSPA/Client
Bumps [ua-parser-js](https://github.com/faisalman/ua-parser-js) from 0.7.31 to 0.7.33.
- [Release notes](https://github.com/faisalman/ua-parser-js/releases)
- [Changelog](https://github.com/faisalman/ua-parser-js/blob/master/changelog.md)
- [Commits](https://github.com/faisalman/ua-parser-js/compare/0.7.31...0.7.33)

---
updated-dependencies:
- dependency-name: ua-parser-js
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-27 10:08:16 +00:00
dependabot[bot]
dd18f8df55
Bump json5 from 1.0.1 to 1.0.2 in /src/Web/WebSPA/Client
Bumps [json5](https://github.com/json5/json5) from 1.0.1 to 1.0.2.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v1.0.1...v1.0.2)

---
updated-dependencies:
- dependency-name: json5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-07 19:26:34 +00:00
dependabot[bot]
8bfb1bd06b
Bump express from 4.17.2 to 4.18.2 in /src/Web/WebSPA/Client
Bumps [express](https://github.com/expressjs/express) from 4.17.2 to 4.18.2.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.17.2...4.18.2)

---
updated-dependencies:
- dependency-name: express
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-15 18:49:44 +00:00
Tarun Jain
0f2ade49fb Merge branch 'net7-duende-fix' of https://github.com/erjain/eShopOnContainers into net7-duende-fix 2022-12-14 18:08:33 +05:30
Tarun Jain
9a5ea85223 Update seed data with card expiration date 2022-12-14 18:08:19 +05:30
Tarun Jain
365077a191
Merge branch 'dev' into net7-duende-fix 2022-12-14 18:03:52 +05:30
Tarun Jain
e4f2b62b5e update 7.0 sdk 2022-12-13 20:57:32 +05:30
Tarun Jain
a464a6996e fix authentication issue in identity.api 2022-12-13 18:18:06 +05:30
dependabot[bot]
6a00e8bb9b
Bump decode-uri-component from 0.2.0 to 0.2.2 in /src/Web/WebSPA/Client
Bumps [decode-uri-component](https://github.com/SamVerschueren/decode-uri-component) from 0.2.0 to 0.2.2.
- [Release notes](https://github.com/SamVerschueren/decode-uri-component/releases)
- [Commits](https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.0...v0.2.2)

---
updated-dependencies:
- dependency-name: decode-uri-component
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-07 16:24:16 +00:00
Tarun Jain
892da8b2c2 update devspaces.support to .NET 7 2022-12-06 00:08:40 +05:30
Tarun Jain
3a03508f8a minor fixes 2022-12-02 02:01:14 +05:30
Tarun Jain
b90d2d1cd4 implement Duende.IdentityServer 6.2.0 2022-11-30 21:55:07 +05:30
Tarun Jain
c10fff488c fix serilog error 2022-11-29 02:56:34 +05:30
Tarun Jain
9b3e00d756 update nuget packages for complete solution 2022-11-29 00:56:35 +05:30
Tarun Jain
b5b667b385 commit to update IdentityServer 3.1 to Duende.IdentityServer 6.2.0 2022-11-28 17:32:59 +05:30
Tarun Jain
4596d7aa99
Merge pull request #2005 from dotnet-architecture/dependabot/nuget/src/BuildingBlocks/WebHostCustomization/WebHost.Customization/System.Data.SqlClient-4.8.5
Bump System.Data.SqlClient from 4.8.2 to 4.8.5 in /src/BuildingBlocks/WebHostCustomization/WebHost.Customization
2022-11-22 21:20:29 +05:30
Tarun Jain
b8cc0d2cff
Merge pull request #2003 from dotnet-architecture/dependabot/npm_and_yarn/src/Web/WebSPA/Client/engine.io-and-socket.io-6.2.1
Bump engine.io and socket.io in /src/Web/WebSPA/Client
2022-11-22 21:18:54 +05:30
dependabot[bot]
2e7f6823ab
Bump engine.io and socket.io in /src/Web/WebSPA/Client
Bumps [engine.io](https://github.com/socketio/engine.io) and [socket.io](https://github.com/socketio/socket.io). These dependencies needed to be updated together.

Updates `engine.io` from 6.1.2 to 6.2.1
- [Release notes](https://github.com/socketio/engine.io/releases)
- [Changelog](https://github.com/socketio/engine.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/engine.io/compare/6.1.2...6.2.1)

Updates `socket.io` from 4.4.1 to 4.5.3
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/4.4.1...4.5.3)

---
updated-dependencies:
- dependency-name: engine.io
  dependency-type: indirect
- dependency-name: socket.io
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-22 15:43:35 +00:00
dependabot[bot]
c80ee1ea62
Bump System.Data.SqlClient
Bumps [System.Data.SqlClient](https://github.com/dotnet/corefx) from 4.8.2 to 4.8.5.
- [Release notes](https://github.com/dotnet/corefx/releases)
- [Commits](https://github.com/dotnet/corefx/commits)

---
updated-dependencies:
- dependency-name: System.Data.SqlClient
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-22 15:41:44 +00:00
Tarun Jain
70a2548d8b
Merge pull request #2004 from dotnet-architecture/dependabot/nuget/src/Services/Ordering/Ordering.BackgroundTasks/System.Data.SqlClient-4.8.5
Bump System.Data.SqlClient from 4.8.2 to 4.8.5 in /src/Services/Ordering/Ordering.BackgroundTasks
2022-11-22 21:11:15 +05:30
Tarun Jain
2f2cf83167
Merge pull request #1999 from dotnet-architecture/dependabot/npm_and_yarn/src/Web/WebSPA/Client/loader-utils-1.4.2
Bump loader-utils from 1.1.0 to 1.4.2 in /src/Web/WebSPA/Client
2022-11-22 21:07:52 +05:30
dependabot[bot]
74830148f5
Bump System.Data.SqlClient
Bumps [System.Data.SqlClient](https://github.com/dotnet/corefx) from 4.8.2 to 4.8.5.
- [Release notes](https://github.com/dotnet/corefx/releases)
- [Commits](https://github.com/dotnet/corefx/commits)

---
updated-dependencies:
- dependency-name: System.Data.SqlClient
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-22 15:36:55 +00:00
Tarun Jain
911d7329b0
Merge pull request #1998 from dotnet-architecture/dependabot/npm_and_yarn/src/Web/WebSPA/Client/socket.io-parser-4.0.5
Bump socket.io-parser from 4.0.4 to 4.0.5 in /src/Web/WebSPA/Client
2022-11-22 21:06:15 +05:30
dependabot[bot]
970f63cbe1
Bump loader-utils from 1.1.0 to 1.4.2 in /src/Web/WebSPA/Client
Bumps [loader-utils](https://github.com/webpack/loader-utils) from 1.1.0 to 1.4.2.
- [Release notes](https://github.com/webpack/loader-utils/releases)
- [Changelog](https://github.com/webpack/loader-utils/blob/v1.4.2/CHANGELOG.md)
- [Commits](https://github.com/webpack/loader-utils/compare/v1.1.0...v1.4.2)

---
updated-dependencies:
- dependency-name: loader-utils
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-11 07:51:32 +00:00
dependabot[bot]
956f80a4ce
Bump socket.io-parser from 4.0.4 to 4.0.5 in /src/Web/WebSPA/Client
Bumps [socket.io-parser](https://github.com/socketio/socket.io-parser) from 4.0.4 to 4.0.5.
- [Release notes](https://github.com/socketio/socket.io-parser/releases)
- [Changelog](https://github.com/socketio/socket.io-parser/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io-parser/compare/4.0.4...4.0.5)

---
updated-dependencies:
- dependency-name: socket.io-parser
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-09 22:37:39 +00:00
Tarun Jain
2de2ddc041 update identity.api 2022-11-07 12:45:49 +05:30
Tarun Jain
390d737235 update webhooks.api 2022-10-27 20:17:06 +05:30
Tarun Jain
218759a5de update webapps 2022-10-27 18:55:55 +05:30
Tarun Jain
e38abbfba8 update Services\Ordering and services\Catalog 2022-10-27 17:56:07 +05:30
Tarun Jain
ea24ac57bf update basket.api, Basket.UnitTests, Basket.FunctionalTests & Application.FunctionalTests 2022-10-11 17:03:47 +05:30
566 changed files with 36790 additions and 53390 deletions

132
.editorconfig Normal file
View File

@ -0,0 +1,132 @@
###############################
# Core EditorConfig Options #
###############################
root = true
# All files
[*]
indent_style = space
# XML project files
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
indent_size = 2
# XML config files
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
indent_size = 2
# Code files
[*.{cs,csx,vb,vbx}]
indent_size = 4
insert_final_newline = true
charset = utf-8-bom
###############################
# .NET Coding Conventions #
###############################
[*.{cs,vb}]
# Organize usings
dotnet_sort_system_directives_first = true
# this. preferences
dotnet_style_qualification_for_field = false:silent
dotnet_style_qualification_for_property = false:silent
dotnet_style_qualification_for_method = false:silent
dotnet_style_qualification_for_event = false:silent
# Language keywords vs BCL types preferences
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
dotnet_style_predefined_type_for_member_access = true:silent
# Parentheses preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
# Modifier preferences
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
dotnet_style_readonly_field = true:suggestion
# Expression-level preferences
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_auto_properties = true:silent
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_prefer_conditional_expression_over_return = true:silent
###############################
# Naming Conventions #
###############################
# Style Definitions
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
# Use PascalCase for constant fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
dotnet_naming_symbols.constant_fields.required_modifiers = const
###############################
# C# Coding Conventions #
###############################
[*.cs]
# var preferences
csharp_style_var_for_built_in_types = true:silent
csharp_style_var_when_type_is_apparent = true:silent
csharp_style_var_elsewhere = true:silent
# Expression-bodied members
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_accessors = true:silent
# Pattern matching preferences
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
# Null-checking preferences
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion
# Modifier preferences
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
# Expression-level preferences
csharp_prefer_braces = true:silent
csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_prefer_simple_default_expression = true:suggestion
csharp_style_prefer_local_over_anonymous_function = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
###############################
# C# Formatting Rules #
###############################
# New line preferences
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true
# Indentation preferences
csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_labels = flush_left
# Space preferences
csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_around_binary_operators = before_and_after
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
# Wrapping preferences
csharp_preserve_single_line_statements = true
csharp_preserve_single_line_blocks = true
###############################
# VB Coding Conventions #
###############################
[*.vb]
# Modifier preferences
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion

View File

@ -22,7 +22,7 @@ on:
env:
SERVICE: catalog-api
IMAGE: catalog.api
DOTNET_VERSION: 6.0.x
DOTNET_VERSION: 7.0.x
PROJECT_PATH: Services/Catalog/Catalog.API
TESTS_PATH: Services/Catalog/Catalog.UnitTests

View File

@ -22,7 +22,7 @@ on:
env:
SERVICE: ordering-api
IMAGE: ordering.api
DOTNET_VERSION: 6.0.x
DOTNET_VERSION: 7.0.x
PROJECT_PATH: Services/Ordering/Ordering.API
TESTS_PATH: Services/Ordering/Ordering.UnitTests

2
.gitignore vendored
View File

@ -281,3 +281,5 @@ pub/
src/**/app.yaml
src/**/inf.yaml
.angular/
/src/Services/Identity/Identity.API/keys/*.json

View File

@ -47,7 +47,7 @@ All contributions must be submitted as a [Pull Request (PR)](https://help.github
The main branches are **`dev`** and **`master`**:
- **`dev`**: Contains the latest code **and it is the branch actively developed**.
**All PRs must be against `dev` branch to be considered**. This branch is developed using `.NET 5`
**All PRs must be against `dev` branch to be considered**. This branch is developed using `.NET 7`
- **`main`**: Synced from time to time from **`dev`**. It contains "stable" code.This branch contains changes specific to `.NET Core 3.1` (**Keep in mind "stable" does not mean PRODUCTION-READY!**)

View File

@ -72,9 +72,9 @@ In the future, more features will be implemented in the advanced scenario.
**NEWS / ANNOUNCEMENTS**
Do you want to be up-to-date on .NET Architecture guidance and reference apps like eShopOnContainers? --> Subscribe by "WATCHING" this new GitHub repo: https://github.com/dotnet-architecture/News
## Updated for .NET 6
## Updated for .NET 7
eShopOnContainers is updated to .NET 6 "wave" of technologies. Not just compilation but also new recommended code in EF Core, ASP.NET Core, and other new related versions with several significant changes.
eShopOnContainers is updated to .NET 7 "wave" of technologies. Not just compilation but also new recommended code in EF Core, ASP.NET Core, and other new related versions with several significant changes.
**See more details in the [Release notes](https://github.com/dotnet-architecture/eShopOnContainers/wiki/Release-notes) wiki page**.
@ -86,7 +86,7 @@ eShopOnContainers is updated to .NET 6 "wave" of technologies. Not just compilat
### Architecture overview
This reference application is cross-platform at the server and client-side, thanks to .NET 6 services capable of running on Linux or Windows containers depending on your Docker host, and to Xamarin for mobile apps running on Android, iOS, or Windows/UWP plus any browser for the client web apps.
This reference application is cross-platform at the server and client-side, thanks to .NET 7 services capable of running on Linux or Windows containers depending on your Docker host, and to Xamarin for mobile apps running on Android, iOS, or Windows/UWP plus any browser for the client web apps.
The architecture proposes a microservice oriented architecture implementation with multiple autonomous microservices (each one owning its own data/db) and implementing different approaches within each microservice (simple CRUD vs. DDD/CQRS patterns) using HTTP as the communication protocol between the client apps and the microservices and supports asynchronous communication for data updates propagation across multiple services based on Integration Events and an Event Bus (a light message broker, to choose between RabbitMQ or Azure Service Bus, underneath) plus other features defined at the [roadmap](https://github.com/dotnet-architecture/eShopOnContainers/wiki/Roadmap).
![](img/eshop_logo.png)

View File

@ -2,7 +2,8 @@
Following are the most important branches:
- `dev`: Contains the latest code **and it is the branch actively developed**. Note that **all PRs must be against the `dev` branch to be considered**. This branch is developed using `.NET 6`
- `dev`: Contains the latest code **and it is the branch actively developed**. Note that **all PRs must be against the `dev` branch to be considered**. This branch is developed using `.NET 7`
- `release/net-6`: Contains the code changes specific to the `.NET 6`
- `release/net-5`: Contains the code changes specific to the `.NET 5`
- `release/net-3.1.1`: Contains the code changes specific to the `.NET 3.1`

View File

@ -13,7 +13,7 @@ metadata:
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
data:
catalog__ConnectionString: Server={{ $sqlsrv }};Initial Catalog={{ .Values.inf.sql.catalog.db }};User Id={{ .Values.inf.sql.common.user }};Password={{ .Values.inf.sql.common.pwd }};
catalog__ConnectionString: Server={{ $sqlsrv }};Initial Catalog={{ .Values.inf.sql.catalog.db }};User Id={{ .Values.inf.sql.common.user }};Password={{ .Values.inf.sql.common.pwd }};TrustServerCertificate={{ .Values.inf.sql.common.TrustServerCertificate }};
catalog__PicBaseUrl: {{ $protocol }}://{{ $webshoppingapigw }}/c/api/v1/catalog/items/[0]/pic/
catalog__AzureStorageEnabled: "{{ .Values.inf.misc.useAzureStorage }}"
all__EventBusConnection: {{ .Values.inf.eventbus.constr }}

View File

@ -20,7 +20,7 @@ metadata:
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
data:
identity__ConnectionString: Server={{ $sqlsrv }};Initial Catalog={{ .Values.inf.sql.identity.db }};User Id={{ .Values.inf.sql.common.user }};Password={{ .Values.inf.sql.common.pwd }};
identity__ConnectionString: Server={{ $sqlsrv }};Initial Catalog={{ .Values.inf.sql.identity.db }};User Id={{ .Values.inf.sql.common.user }};Password={{ .Values.inf.sql.common.pwd }};TrustServerCertificate={{ .Values.inf.sql.common.TrustServerCertificate }};
identity__keystore: {{ .Values.inf.redis.keystore.constr }}
all__InstrumentationKey: "{{ .Values.inf.appinsights.key }}"
mvc_e: http://{{ $mvc_url }}

View File

@ -13,6 +13,7 @@ inf:
user: sa # SQL user
pwd: Pass@word # SQL pwd
pid: Developer
TrustServerCertificate: true
catalog: # inf.sql.catalog: settings for the catalog-api sql (user, pwd, db)
db: CatalogDb # Catalog API SQL db name
ordering: # inf.sql.ordering: settings for the ordering-api sql (user, pwd, db)

View File

@ -11,7 +11,7 @@ metadata:
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
data:
ordering__ConnectionString: Server={{ $sqlsrv }};Initial Catalog={{ .Values.inf.sql.ordering.db }};User Id={{ .Values.inf.sql.common.user }};Password={{ .Values.inf.sql.common.pwd }};
ordering__ConnectionString: Server={{ $sqlsrv }};Initial Catalog={{ .Values.inf.sql.ordering.db }};User Id={{ .Values.inf.sql.common.user }};Password={{ .Values.inf.sql.common.pwd }};TrustServerCertificate={{ .Values.inf.sql.common.TrustServerCertificate }};
urls__IdentityUrl: http://{{ .Values.app.svc.identity }}
all__EventBusConnection: {{ .Values.inf.eventbus.constr }}
all__InstrumentationKey: "{{ .Values.inf.appinsights.key }}"

View File

@ -12,7 +12,7 @@ metadata:
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
data:
ordering__ConnectionString: Server={{ $sqlsrv }};Initial Catalog={{ .Values.inf.sql.ordering.db }};User Id={{ .Values.inf.sql.common.user }};Password={{ .Values.inf.sql.common.pwd }};
ordering__ConnectionString: Server={{ $sqlsrv }};Initial Catalog={{ .Values.inf.sql.ordering.db }};User Id={{ .Values.inf.sql.common.user }};Password={{ .Values.inf.sql.common.pwd }};TrustServerCertificate={{ .Values.inf.sql.common.TrustServerCertificate }};
ordering__EnableLoadTest: "{{ .Values.inf.misc.useLoadTest }}"
all__EventBusConnection: {{ .Values.inf.eventbus.constr }}
all__InstrumentationKey: "{{ .Values.inf.appinsights.key }}"

View File

@ -13,7 +13,7 @@ metadata:
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
data:
webhooks__ConnectionString: Server={{ $sqlsrv }};Initial Catalog={{ .Values.inf.sql.webhooks.db }};User Id={{ .Values.inf.sql.common.user }};Password={{ .Values.inf.sql.common.pwd }};
webhooks__ConnectionString: Server={{ $sqlsrv }};Initial Catalog={{ .Values.inf.sql.webhooks.db }};User Id={{ .Values.inf.sql.common.user }};Password={{ .Values.inf.sql.common.pwd }};TrustServerCertificate={{ .Values.inf.sql.common.TrustServerCertificate }};
urls__IdentityUrl: http://{{ $identity }}
urls__IdentityUrlExternal: {{ $protocol }}://{{ $identity }}
all__EventBusConnection: {{ .Values.inf.eventbus.constr }}

BIN
gothrough docs.docx Normal file

Binary file not shown.

View File

@ -6,15 +6,15 @@
# Use this values to run the app locally in Windows
ESHOP_EXTERNAL_DNS_NAME_OR_IP=host.docker.internal
ESHOP_STORAGE_CATALOG_URL=http://host.docker.internal:5202/c/api/v1/catalog/items/[0]/pic/
ESHOP_STORAGE_CATALOG_URL=http://host.docker.internal:5121/c/api/v1/catalog/items/[0]/pic/
# Use this values to run the app locally in Mac
# ESHOP_EXTERNAL_DNS_NAME_OR_IP=docker.for.mac.localhost
# ESHOP_STORAGE_CATALOG_URL=http://docker.for.mac.localhost:5202/c/api/v1/catalog/items/[0]/pic/
# ESHOP_STORAGE_CATALOG_URL=http://docker.for.mac.localhost:5121/c/api/v1/catalog/items/[0]/pic/
# Use this values to run the app locally in Linux
# ESHOP_EXTERNAL_DNS_NAME_OR_IP=docker.for.linux.localhost
# ESHOP_STORAGE_CATALOG_URL=http://docker.for.linux.localhost:5202/c/api/v1/catalog/items/[0]/pic/
# ESHOP_STORAGE_CATALOG_URL=http://docker.for.linux.localhost:5121/c/api/v1/catalog/items/[0]/pic/
# Configure this values to the cloud storage locations
# ESHOP_STORAGE_CATALOG_URL=<YourAzureStorage_Catalog_BLOB_URL>

View File

@ -1,139 +0,0 @@
admin:
access_log_path: "/dev/null"
address:
socket_address:
address: 0.0.0.0
port_value: 8001
static_resources:
listeners:
- address:
socket_address:
address: 0.0.0.0
port_value: 80
filter_chains:
- filters:
- name: envoy.http_connection_manager
config:
codec_type: auto
stat_prefix: ingress_http
route_config:
name: eshop_backend_route
virtual_hosts:
- name: eshop_backend
domains:
- "*"
routes:
- name: "c-short"
match:
prefix: "/c/"
route:
auto_host_rewrite: true
prefix_rewrite: "/catalog-api/"
cluster: catalog
- name: "c-long"
match:
prefix: "/catalog-api/"
route:
auto_host_rewrite: true
cluster: catalog
- name: "o-short"
match:
prefix: "/o/"
route:
auto_host_rewrite: true
prefix_rewrite: "/ordering-api/"
cluster: ordering
- name: "o-long"
match:
prefix: "/ordering-api/"
route:
auto_host_rewrite: true
cluster: ordering
- name: "h-long"
match:
prefix: "/hub/notificationhub"
route:
auto_host_rewrite: true
cluster: signalr-hub
timeout: 300s
- name: "b-short"
match:
prefix: "/b/"
route:
auto_host_rewrite: true
prefix_rewrite: "/basket-api/"
cluster: basket
- name: "b-long"
match:
prefix: "/basket-api/"
route:
auto_host_rewrite: true
cluster: basket
- name: "agg"
match:
prefix: "/"
route:
auto_host_rewrite: true
prefix_rewrite: "/"
cluster: shoppingagg
http_filters:
- name: envoy.router
access_log:
- name: envoy.file_access_log
filter:
not_health_check_filter: {}
config:
json_format:
time: "%START_TIME%"
protocol: "%PROTOCOL%"
duration: "%DURATION%"
request_method: "%REQ(:METHOD)%"
request_host: "%REQ(HOST)%"
path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"
response_flags: "%RESPONSE_FLAGS%"
route_name: "%ROUTE_NAME%"
upstream_host: "%UPSTREAM_HOST%"
upstream_cluster: "%UPSTREAM_CLUSTER%"
upstream_local_address: "%UPSTREAM_LOCAL_ADDRESS%"
path: "/tmp/access.log"
clusters:
- name: shoppingagg
connect_timeout: 0.25s
type: strict_dns
lb_policy: round_robin
hosts:
- socket_address:
address: mobileshoppingagg
port_value: 80
- name: catalog
connect_timeout: 0.25s
type: strict_dns
lb_policy: round_robin
hosts:
- socket_address:
address: catalog-api
port_value: 80
- name: basket
connect_timeout: 0.25s
type: strict_dns
lb_policy: round_robin
hosts:
- socket_address:
address: basket-api
port_value: 80
- name: ordering
connect_timeout: 0.25s
type: strict_dns
lb_policy: round_robin
hosts:
- socket_address:
address: ordering-api
port_value: 80
- name: signalr-hub
connect_timeout: 0.25s
type: strict_dns
lb_policy: round_robin
hosts:
- socket_address:
address: ordering-signalrhub
port_value: 80

View File

@ -1,142 +0,0 @@
admin:
access_log_path: "/dev/null"
address:
socket_address:
address: 0.0.0.0
port_value: 8001
static_resources:
listeners:
- address:
socket_address:
address: 0.0.0.0
port_value: 80
filter_chains:
- filters:
- name: envoy.http_connection_manager
config:
codec_type: auto
stat_prefix: ingress_http
route_config:
name: eshop_backend_route
virtual_hosts:
- name: eshop_backend
domains:
- "*"
routes:
- name: "c-short"
match:
prefix: "/c/"
route:
auto_host_rewrite: true
prefix_rewrite: "/catalog-api/"
cluster: catalog
- name: "c-long"
match:
prefix: "/catalog-api/"
route:
auto_host_rewrite: true
cluster: catalog
- name: "o-short"
match:
prefix: "/o/"
route:
auto_host_rewrite: true
prefix_rewrite: "/ordering-api/"
cluster: ordering
- name: "o-long"
match:
prefix: "/ordering-api/"
route:
auto_host_rewrite: true
cluster: ordering
- name: "h-long"
match:
prefix: "/hub/notificationhub"
route:
auto_host_rewrite: true
cluster: signalr-hub
timeout: 300s
upgrade_configs:
upgrade_type: "websocket"
enabled: true
- name: "b-short"
match:
prefix: "/b/"
route:
auto_host_rewrite: true
prefix_rewrite: "/basket-api/"
cluster: basket
- name: "b-long"
match:
prefix: "/basket-api/"
route:
auto_host_rewrite: true
cluster: basket
- name: "agg"
match:
prefix: "/"
route:
auto_host_rewrite: true
prefix_rewrite: "/"
cluster: shoppingagg
http_filters:
- name: envoy.router
access_log:
- name: envoy.file_access_log
filter:
not_health_check_filter: {}
config:
json_format:
time: "%START_TIME%"
protocol: "%PROTOCOL%"
duration: "%DURATION%"
request_method: "%REQ(:METHOD)%"
request_host: "%REQ(HOST)%"
path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"
response_flags: "%RESPONSE_FLAGS%"
route_name: "%ROUTE_NAME%"
upstream_host: "%UPSTREAM_HOST%"
upstream_cluster: "%UPSTREAM_CLUSTER%"
upstream_local_address: "%UPSTREAM_LOCAL_ADDRESS%"
path: "/tmp/access.log"
clusters:
- name: shoppingagg
connect_timeout: 0.25s
type: strict_dns
lb_policy: round_robin
hosts:
- socket_address:
address: webshoppingagg
port_value: 80
- name: catalog
connect_timeout: 0.25s
type: strict_dns
lb_policy: round_robin
hosts:
- socket_address:
address: catalog-api
port_value: 80
- name: basket
connect_timeout: 0.25s
type: strict_dns
lb_policy: round_robin
hosts:
- socket_address:
address: basket-api
port_value: 80
- name: ordering
connect_timeout: 0.25s
type: strict_dns
lb_policy: round_robin
hosts:
- socket_address:
address: ordering-api
port_value: 80
- name: signalr-hub
connect_timeout: 0.25s
type: strict_dns
lb_policy: round_robin
hosts:
- socket_address:
address: ordering-signalrhub
port_value: 80

View File

@ -16,8 +16,7 @@ public class BasketController : ControllerBase
[HttpPost]
[HttpPut]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(BasketData), (int)HttpStatusCode.OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<BasketData>> UpdateAllBasketAsync([FromBody] UpdateBasketRequest data)
{
if (data.Items == null || !data.Items.Any())
@ -73,8 +72,7 @@ public class BasketController : ControllerBase
[HttpPut]
[Route("items")]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(BasketData), (int)HttpStatusCode.OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<BasketData>> UpdateQuantitiesAsync([FromBody] UpdateBasketItemsRequest data)
{
if (!data.Updates.Any())
@ -110,8 +108,8 @@ public class BasketController : ControllerBase
[HttpPost]
[Route("items")]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType((int)HttpStatusCode.OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult> AddBasketItemAsync([FromBody] AddBasketItemRequest data)
{
if (data == null || data.Quantity == 0)

View File

@ -1,11 +0,0 @@
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Controllers;
[Route("")]
public class HomeController : Controller
{
[HttpGet]
public IActionResult Index()
{
return new RedirectResult("~/swagger");
}
}

View File

@ -16,8 +16,7 @@ public class OrderController : ControllerBase
[Route("draft/{basketId}")]
[HttpGet]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(OrderData), (int)HttpStatusCode.OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<OrderData>> GetOrderDraftAsync(string basketId)
{
if (string.IsNullOrEmpty(basketId))

View File

@ -1,8 +1,8 @@
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
# It's important to keep lines from here down to "COPY . ." identical in all Dockerfiles
@ -11,7 +11,6 @@ COPY "eShopOnContainers-ServicesAndWebApps.sln" "eShopOnContainers-ServicesAndWe
COPY "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj"
COPY "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj"
COPY "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj"
COPY "BuildingBlocks/EventBus/EventBus/EventBus.csproj" "BuildingBlocks/EventBus/EventBus/EventBus.csproj"
COPY "BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj" "BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj"
COPY "BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj" "BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj"
@ -33,6 +32,8 @@ COPY "Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj"
COPY "Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj" "Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj"
COPY "Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj" "Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj"
COPY "Services/Payment/Payment.API/Payment.API.csproj" "Services/Payment/Payment.API/Payment.API.csproj"
COPY "Services/Services.Common/Services.Common.csproj" "Services/Services.Common/Services.Common.csproj"
COPY "Services/Contact/Contact.API/Contact.API.csproj" "Services/Contact/Contact.API/Contact.API.csproj"
COPY "Services/Webhooks/Webhooks.API/Webhooks.API.csproj" "Services/Webhooks/Webhooks.API/Webhooks.API.csproj"
COPY "Tests/Services/Application.FunctionalTests/Application.FunctionalTests.csproj" "Tests/Services/Application.FunctionalTests/Application.FunctionalTests.csproj"
COPY "Web/WebhookClient/WebhookClient.csproj" "Web/WebhookClient/WebhookClient.csproj"
@ -42,6 +43,7 @@ COPY "Web/WebStatus/WebStatus.csproj" "Web/WebStatus/WebStatus.csproj"
COPY "docker-compose.dcproj" "docker-compose.dcproj"
COPY "Directory.Packages.props" "Directory.Packages.props"
COPY "NuGet.config" "NuGet.config"
RUN dotnet restore "eShopOnContainers-ServicesAndWebApps.sln"

View File

@ -1,4 +1,4 @@
FROM mcr.microsoft.com/dotnet/sdk:6.0
FROM mcr.microsoft.com/dotnet/sdk:7.0
ARG BUILD_CONFIGURATION=Debug
ENV ASPNETCORE_ENVIRONMENT=Development
ENV DOTNET_USE_POLLING_FILE_WATCHER=true
@ -6,7 +6,6 @@ EXPOSE 80
WORKDIR /src
COPY ["src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj", "src/ApiGateways/Mobile.Bff.Shopping/aggregator/"]
COPY ["src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj", "src/BuildingBlocks/Devspaces.Support/"]
COPY ["src/NuGet.config", "src/NuGet.config"]
RUN dotnet restore src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj -nowarn:msb3202,nu1503

View File

@ -0,0 +1,62 @@
internal static class Extensions
{
public static IServiceCollection AddReverseProxy(this IServiceCollection services, IConfiguration configuration)
{
services.AddReverseProxy().LoadFromConfig(configuration.GetRequiredSection("ReverseProxy"));
return services;
}
public static IServiceCollection AddHealthChecks(this IServiceCollection services, IConfiguration configuration)
{
services.AddHealthChecks()
.AddUrlGroup(_ => new Uri(configuration.GetRequiredValue("CatalogUrlHC")), name: "catalogapi-check", tags: new string[] { "catalogapi" })
.AddUrlGroup(_ => new Uri(configuration.GetRequiredValue("OrderingUrlHC")), name: "orderingapi-check", tags: new string[] { "orderingapi" })
.AddUrlGroup(_ => new Uri(configuration.GetRequiredValue("BasketUrlHC")), name: "basketapi-check", tags: new string[] { "basketapi" })
.AddUrlGroup(_ => new Uri(configuration.GetRequiredValue("IdentityUrlHC")), name: "identityapi-check", tags: new string[] { "identityapi" });
return services;
}
public static IServiceCollection AddApplicationServices(this IServiceCollection services)
{
// Register delegating handlers
services.AddTransient<HttpClientAuthorizationDelegatingHandler>();
// Register http services
services.AddHttpClient<IOrderApiClient, OrderApiClient>()
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>();
return services;
}
public static IServiceCollection AddGrpcServices(this IServiceCollection services)
{
services.AddTransient<GrpcExceptionInterceptor>();
services.AddScoped<IBasketService, BasketService>();
services.AddGrpcClient<Basket.BasketClient>((services, options) =>
{
var basketApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcBasket;
options.Address = new Uri(basketApi);
}).AddInterceptor<GrpcExceptionInterceptor>();
services.AddScoped<ICatalogService, CatalogService>();
services.AddGrpcClient<Catalog.CatalogClient>((services, options) =>
{
var catalogApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcCatalog;
options.Address = new Uri(catalogApi);
}).AddInterceptor<GrpcExceptionInterceptor>();
services.AddScoped<IOrderingService, OrderingService>();
services.AddGrpcClient<GrpcOrdering.OrderingGrpc.OrderingGrpcClient>((services, options) =>
{
var orderingApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcOrdering;
options.Address = new Uri(orderingApi);
}).AddInterceptor<GrpcExceptionInterceptor>();
return services;
}
}

View File

@ -1,33 +0,0 @@
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Filters
{
namespace Basket.API.Infrastructure.Filters
{
public class AuthorizeCheckOperationFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
// Check for authorize attribute
var hasAuthorize = context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any() ||
context.MethodInfo.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any();
if (!hasAuthorize) return;
operation.Responses.TryAdd("401", new OpenApiResponse { Description = "Unauthorized" });
operation.Responses.TryAdd("403", new OpenApiResponse { Description = "Forbidden" });
var oAuthScheme = new OpenApiSecurityScheme
{
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" }
};
operation.Security = new List<OpenApiSecurityRequirement>
{
new()
{
[ oAuthScheme ] = new [] { "Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator" }
}
};
}
}
}
}

View File

@ -1,41 +1,13 @@
global using CatalogApi;
global using Devspaces.Support;
global using Grpc.Core.Interceptors;
global using System.Text.Json;
global using CatalogApi;
global using Grpc.Core;
global using Grpc.Core.Interceptors;
global using GrpcBasket;
global using GrpcOrdering;
global using HealthChecks.UI.Client;
global using Microsoft.AspNetCore.Authentication.JwtBearer;
global using Microsoft.AspNetCore.Authentication;
global using Microsoft.AspNetCore.Authorization;
global using Microsoft.AspNetCore.Builder;
global using Microsoft.AspNetCore.Diagnostics.HealthChecks;
global using Microsoft.AspNetCore.Hosting;
global using Microsoft.AspNetCore.Http;
global using Microsoft.AspNetCore.Mvc;
global using Microsoft.AspNetCore;
global using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config;
global using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Filters.Basket.API.Infrastructure.Filters;
global using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastructure;
global using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
global using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services;
global using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator;
global using Microsoft.Extensions.Configuration;
global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.Diagnostics.HealthChecks;
global using Microsoft.Extensions.Hosting;
global using Microsoft.Extensions.Logging;
global using Microsoft.Extensions.Options;
global using Microsoft.OpenApi.Models;
global using Serilog;
global using Swashbuckle.AspNetCore.SwaggerGen;
global using System.Collections.Generic;
global using System.IdentityModel.Tokens.Jwt;
global using System.Linq;
global using System.Net.Http.Headers;
global using System.Net.Http;
global using System.Net;
global using System.Text.Json;
global using System.Threading.Tasks;
global using System.Threading;
global using System;
global using Services.Common;

View File

@ -28,7 +28,7 @@ public class GrpcExceptionInterceptor : Interceptor
}
catch (RpcException e)
{
_logger.LogError("Error calling via grpc: {Status} - {Message}", e.Status, e.Message);
_logger.LogError(e, "Error calling via gRPC: {Status}", e.Status);
return default;
}
}

View File

@ -1,44 +0,0 @@
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastructure;
public class HttpClientAuthorizationDelegatingHandler : DelegatingHandler
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ILogger<HttpClientAuthorizationDelegatingHandler> _logger;
public HttpClientAuthorizationDelegatingHandler(IHttpContextAccessor httpContextAccessor, ILogger<HttpClientAuthorizationDelegatingHandler> logger)
{
_httpContextAccessor = httpContextAccessor;
_logger = logger;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Version = new System.Version(2, 0);
request.Method = HttpMethod.Get;
var authorizationHeader = _httpContextAccessor.HttpContext
.Request.Headers["Authorization"];
if (!string.IsNullOrEmpty(authorizationHeader))
{
request.Headers.Add("Authorization", new List<string>() { authorizationHeader });
}
var token = await GetToken();
if (token != null)
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
}
return await base.SendAsync(request, cancellationToken);
}
async Task<string> GetToken()
{
const string ACCESS_TOKEN = "access_token";
return await _httpContextAccessor.HttpContext
.GetTokenAsync(ACCESS_TOKEN);
}
}

View File

@ -1,36 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<AssemblyName>Mobile.Shopping.HttpAggregator</AssemblyName>
<RootNamespace>Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator</RootNamespace>
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
<GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks>
<IsTransformWebConfigDisabled>true</IsTransformWebConfigDisabled>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
<PackageReference Include="Yarp.ReverseProxy" />
<PackageReference Include="AspNetCore.HealthChecks.Uris" />
<PackageReference Include="Google.Protobuf" />
<PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" />
<PackageReference Include="Grpc.Tools" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="5.0.1" />
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="5.0.1" />
<PackageReference Include="Google.Protobuf" Version="3.15.0" />
<PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="2.34.0" />
<PackageReference Include="Grpc.Core" Version="2.34.0" />
<PackageReference Include="Grpc.Net.ClientFactory" Version="2.34.0" />
<PackageReference Include="Grpc.Tools" Version="2.34.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.9" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="5.0.2" />
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.0-dev-00834" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\Devspaces.Support\Devspaces.Support.csproj" />
<ProjectReference Include="..\..\..\Services\Services.Common\Services.Common.csproj" />
</ItemGroup>
<ItemGroup>

View File

@ -2,7 +2,6 @@
public class UpdateBasketItemsRequest
{
public string BasketId { get; set; }
public ICollection<UpdateBasketItemData> Updates { get; set; }

View File

@ -1,23 +1,24 @@
await BuildWebHost(args).RunAsync();
IWebHost BuildWebHost(string[] args) =>
WebHost
.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(cb =>
{
var sources = cb.Sources;
sources.Insert(3, new Microsoft.Extensions.Configuration.Json.JsonConfigurationSource()
{
Optional = true,
Path = "appsettings.localhost.json",
ReloadOnChange = false
});
})
.UseStartup<Startup>()
.UseSerilog((builderContext, config) =>
{
config
.MinimumLevel.Information()
.Enrich.FromLogContext()
.WriteTo.Console();
})
.Build();
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults();
builder.Services.AddReverseProxy(builder.Configuration);
builder.Services.AddControllers();
builder.Services.AddHealthChecks(builder.Configuration);
builder.Services.AddApplicationServices();
builder.Services.AddGrpcServices();
builder.Services.Configure<UrlsConfig>(builder.Configuration.GetSection("urls"));
var app = builder.Build();
app.UseServiceDefaults();
app.UseHttpsRedirection();
app.MapControllers();
app.MapReverseProxy();
await app.RunAsync();

View File

@ -24,13 +24,6 @@
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:61632/"
},
"Azure Dev Spaces": {
"commandName": "AzureDevSpaces",
"launchBrowser": true,
"resourceGroup": "eshoptestedu",
"aksName": "eshoptestedu",
"subscriptionId": "e3035ac1-c06c-4daf-8939-57b3c5f1f759"
}
}
}

View File

@ -5,5 +5,4 @@ public interface IBasketService
Task<BasketData> GetByIdAsync(string id);
Task UpdateAsync(BasketData currentBasket);
}

View File

@ -23,9 +23,6 @@ public class OrderApiClient : IOrderApiClient
var ordersDraftResponse = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<OrderData>(ordersDraftResponse, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
return JsonSerializer.Deserialize<OrderData>(ordersDraftResponse, JsonDefaults.CaseInsensitiveOptions);
}
}

View File

@ -2,10 +2,10 @@
public class OrderingService : IOrderingService
{
private readonly OrderingGrpc.OrderingGrpcClient _orderingGrpcClient;
private readonly GrpcOrdering.OrderingGrpc.OrderingGrpcClient _orderingGrpcClient;
private readonly ILogger<OrderingService> _logger;
public OrderingService(OrderingGrpc.OrderingGrpcClient orderingGrpcClient, ILogger<OrderingService> logger)
public OrderingService(GrpcOrdering.OrderingGrpc.OrderingGrpcClient orderingGrpcClient, ILogger<OrderingService> logger)
{
_orderingGrpcClient = orderingGrpcClient;
_logger = logger;
@ -48,14 +48,14 @@ public class OrderingService : IOrderingService
return data;
}
private CreateOrderDraftCommand MapToOrderDraftCommand(BasketData basketData)
private GrpcOrdering.CreateOrderDraftCommand MapToOrderDraftCommand(BasketData basketData)
{
var command = new CreateOrderDraftCommand
var command = new GrpcOrdering.CreateOrderDraftCommand
{
BuyerId = basketData.BuyerId,
};
basketData.Items.ForEach(i => command.Items.Add(new BasketItem
basketData.Items.ForEach(i => command.Items.Add(new GrpcOrdering.BasketItem
{
Id = i.Id,
OldUnitPrice = (double)i.OldUnitPrice,

View File

@ -1,196 +0,0 @@
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator;
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks()
.AddCheck("self", () => HealthCheckResult.Healthy())
.AddUrlGroup(new Uri(Configuration["CatalogUrlHC"]), name: "catalogapi-check", tags: new string[] { "catalogapi" })
.AddUrlGroup(new Uri(Configuration["OrderingUrlHC"]), name: "orderingapi-check", tags: new string[] { "orderingapi" })
.AddUrlGroup(new Uri(Configuration["BasketUrlHC"]), name: "basketapi-check", tags: new string[] { "basketapi" })
.AddUrlGroup(new Uri(Configuration["IdentityUrlHC"]), name: "identityapi-check", tags: new string[] { "identityapi" })
.AddUrlGroup(new Uri(Configuration["PaymentUrlHC"]), name: "paymentapi-check", tags: new string[] { "paymentapi" });
services.AddCustomMvc(Configuration)
.AddCustomAuthentication(Configuration)
.AddDevspaces()
.AddHttpServices()
.AddGrpcServices();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
var pathBase = Configuration["PATH_BASE"];
if (!string.IsNullOrEmpty(pathBase))
{
loggerFactory.CreateLogger<Startup>().LogDebug("Using PATH BASE '{pathBase}'", pathBase);
app.UsePathBase(pathBase);
}
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseSwagger().UseSwaggerUI(c =>
{
c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1");
c.OAuthClientId("mobileshoppingaggswaggerui");
c.OAuthClientSecret(string.Empty);
c.OAuthRealm(string.Empty);
c.OAuthAppName("Purchase BFF Swagger UI");
});
app.UseRouting();
app.UseCors("CorsPolicy");
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
endpoints.MapControllers();
endpoints.MapHealthChecks("/hc", new HealthCheckOptions()
{
Predicate = _ => true,
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
endpoints.MapHealthChecks("/liveness", new HealthCheckOptions
{
Predicate = r => r.Name.Contains("self")
});
});
}
}
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration)
{
services.AddOptions();
services.Configure<UrlsConfig>(configuration.GetSection("urls"));
services.AddControllers()
.AddJsonOptions(options => options.JsonSerializerOptions.WriteIndented = true);
services.AddSwaggerGen(options =>
{
options.DescribeAllEnumsAsStrings();
options.SwaggerDoc("v1", new OpenApiInfo
{
Title = "Shopping Aggregator for Mobile Clients",
Version = "v1",
Description = "Shopping Aggregator for Mobile Clients"
});
options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows()
{
Implicit = new OpenApiOAuthFlow()
{
AuthorizationUrl = new Uri($"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize"),
TokenUrl = new Uri($"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/token"),
Scopes = new Dictionary<string, string>()
{
{ "mobileshoppingagg", "Shopping Aggregator for Mobile Clients" }
}
}
}
});
options.OperationFilter<AuthorizeCheckOperationFilter>();
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder
.AllowAnyMethod()
.AllowAnyHeader()
.SetIsOriginAllowed((host) => true)
.AllowCredentials());
});
return services;
}
public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub");
var identityUrl = configuration.GetValue<string>("urls:identity");
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Authority = identityUrl;
options.RequireHttpsMetadata = false;
options.Audience = "mobileshoppingagg";
});
return services;
}
public static IServiceCollection AddHttpServices(this IServiceCollection services)
{
//register delegating handlers
services.AddTransient<HttpClientAuthorizationDelegatingHandler>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
//register http services
services.AddHttpClient<IOrderApiClient, OrderApiClient>()
.AddDevspacesSupport();
return services;
}
public static IServiceCollection AddGrpcServices(this IServiceCollection services)
{
services.AddTransient<GrpcExceptionInterceptor>();
services.AddScoped<IBasketService, BasketService>();
services.AddGrpcClient<Basket.BasketClient>((services, options) =>
{
var basketApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcBasket;
options.Address = new Uri(basketApi);
}).AddInterceptor<GrpcExceptionInterceptor>();
services.AddScoped<ICatalogService, CatalogService>();
services.AddGrpcClient<Catalog.CatalogClient>((services, options) =>
{
var catalogApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcCatalog;
options.Address = new Uri(catalogApi);
}).AddInterceptor<GrpcExceptionInterceptor>();
services.AddScoped<IOrderingService, OrderingService>();
services.AddGrpcClient<OrderingGrpc.OrderingGrpcClient>((services, options) =>
{
var orderingApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcOrdering;
options.Address = new Uri(orderingApi);
}).AddInterceptor<GrpcExceptionInterceptor>();
return services;
}
}

View File

@ -1,15 +1,138 @@
{
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"System.Net.Http": "Warning"
}
},
"OpenApi": {
"Endpoint": {
"Name": "Purchase BFF V1"
},
"Document": {
"Description": "Shopping Aggregator for Mobile Clients",
"Title": "Shopping Aggregator for Mobile Clients",
"Version": "v1"
},
"Auth": {
"ClientId": "mobileshoppingaggswaggerui",
"AppName": "Mobile shopping BFF Swagger UI"
}
},
"Identity": {
"Url": "http://localhost:5223",
"Audience": "mobileshoppingagg",
"Scopes": {
"webshoppingagg": "Shopping Aggregator for Mobile Clients"
}
},
"ReverseProxy": {
"Routes": {
"c-short": {
"ClusterId": "catalog",
"Match": {
"Path": "c/{**catch-all}"
},
"Transforms": [
{ "PathRemovePrefix": "/c" }
]
},
"c-long": {
"ClusterId": "catalog",
"Match": {
"Path": "catalog-api/{**catch-all}"
},
"Transforms": [
{ "PathRemovePrefix": "/catalog-api" }
]
},
"b-short": {
"ClusterId": "basket",
"Match": {
"Path": "b/{**catch-all}"
},
"Transforms": [
{ "PathRemovePrefix": "/b" }
]
},
"b-long": {
"ClusterId": "basket",
"Match": {
"Path": "basket-api/{**catch-all}"
},
"Transforms": [
{ "PathRemovePrefix": "/basket-api" }
]
},
"o-short": {
"ClusterId": "orders",
"Match": {
"Path": "o/{**catch-all}"
},
"Transforms": [
{ "PathRemovePrefix": "/o" }
]
},
"o-long": {
"ClusterId": "orders",
"Match": {
"Path": "ordering-api/{**catch-all}"
},
"Transforms": [
{ "PathRemovePrefix": "/ordering-api" }
]
},
"h-long": {
"ClusterId": "signalr",
"Match": {
"Path": "hub/notificationhub/{**catch-all}"
}
}
},
"Console": {
"LogLevel": {
"Default": "Warning"
"Clusters": {
"basket": {
"Destinations": {
"destination0": {
"Address": "http://localhost:5221"
}
}
},
"catalog": {
"Destinations": {
"destination0": {
"Address": "http://localhost:5222"
}
}
},
"orders": {
"Destinations": {
"destination0": {
"Address": "http://localhost:5224"
}
}
},
"signalr": {
"Destinations": {
"destination0": {
"Address": "http://localhost:5225"
}
}
}
}
}
},
"Urls": {
"Basket": "http://localhost:5221",
"Catalog": "http://localhost:5222",
"Orders": "http://localhost:5224",
"Identity": "http://localhost:5223",
"Signalr": "http://localhost:5225",
"GrpcBasket": "http://localhost:6221",
"GrpcCatalog": "http://localhost:6222",
"GrpcOrdering": "http://localhost:6224"
},
"CatalogUrlHC": "http://localhost:5222/hc",
"OrderingUrlHC": "http://localhost:5224/hc",
"BasketUrlHC": "http://localhost:5221/hc",
"IdentityUrlHC": "http://localhost:5223/hc"
}

View File

@ -8,16 +8,19 @@
"grpcCatalog": "http://localhost:81",
"grpcOrdering": "http://localhost:5581"
},
"IdentityUrlExternal": "http://localhost:5105",
"IdentityUrl": "http://localhost:5105",
"Identity": {
"ExternalUrl": "http://localhost:5105",
"Url": "http://localhost:5105",
},
"Logging": {
"IncludeScopes": false,
"Debug": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug"
}
},
"Console": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug"
}

View File

@ -1,55 +0,0 @@
kind: helm-release
apiVersion: 1.1
build:
context: ..\..\..\..
dockerfile: Dockerfile
install:
chart: ../../../../k8s/helm/mobileshoppingagg
set:
image:
tag: $(tag)
pullPolicy: Never
ingress:
annotations:
kubernetes.io/ingress.class: traefik-azds
hosts:
# This expands to [space.s.]apigwms.<guid>.<region>.aksapp.io
- $(spacePrefix)eshop$(hostSuffix)
inf:
k8s:
dns: $(spacePrefix)eshop$(hostSuffix)
values:
- values.dev.yaml?
- secrets.dev.yaml?
- app.yaml
- inf.yaml
configurations:
develop:
build:
useGitIgnore: true
dockerfile: Dockerfile.develop
container:
syncTarget: /src
sync:
- '**/Pages/**'
- '**/Views/**'
- '**/wwwroot/**'
- '!**/*.{sln,csproj}'
command:
- dotnet
- run
- --no-restore
- --no-build
- --no-launch-profile
- -c
- ${Configuration:-Debug}
iterate:
processesToKill:
- dotnet
- vsdbg
buildCommands:
- - dotnet
- build
- --no-restore
- -c
- ${Configuration:-Debug}

View File

@ -16,8 +16,7 @@ public class BasketController : ControllerBase
[HttpPost]
[HttpPut]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(BasketData), (int)HttpStatusCode.OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<BasketData>> UpdateAllBasketAsync([FromBody] UpdateBasketRequest data)
{
if (data.Items == null || !data.Items.Any())
@ -74,8 +73,7 @@ public class BasketController : ControllerBase
[HttpPut]
[Route("items")]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(BasketData), (int)HttpStatusCode.OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<BasketData>> UpdateQuantitiesAsync([FromBody] UpdateBasketItemsRequest data)
{
if (!data.Updates.Any())
@ -109,8 +107,8 @@ public class BasketController : ControllerBase
[HttpPost]
[Route("items")]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType((int)HttpStatusCode.OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult> AddBasketItemAsync([FromBody] AddBasketItemRequest data)
{
if (data == null || data.Quantity == 0)

View File

@ -1,11 +0,0 @@
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers;
[Route("")]
public class HomeController : Controller
{
[HttpGet]
public IActionResult Index()
{
return new RedirectResult("~/swagger");
}
}

View File

@ -16,8 +16,7 @@ public class OrderController : ControllerBase
[Route("draft/{basketId}")]
[HttpGet]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(OrderData), (int)HttpStatusCode.OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<OrderData>> GetOrderDraftAsync(string basketId)
{
if (string.IsNullOrWhiteSpace(basketId))

View File

@ -1,8 +1,8 @@
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
# It's important to keep lines from here down to "COPY . ." identical in all Dockerfiles
@ -11,7 +11,6 @@ COPY "eShopOnContainers-ServicesAndWebApps.sln" "eShopOnContainers-ServicesAndWe
COPY "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj"
COPY "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj"
COPY "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj"
COPY "BuildingBlocks/EventBus/EventBus/EventBus.csproj" "BuildingBlocks/EventBus/EventBus/EventBus.csproj"
COPY "BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj" "BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj"
COPY "BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj" "BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj"
@ -33,6 +32,8 @@ COPY "Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj"
COPY "Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj" "Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj"
COPY "Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj" "Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj"
COPY "Services/Payment/Payment.API/Payment.API.csproj" "Services/Payment/Payment.API/Payment.API.csproj"
COPY "Services/Services.Common/Services.Common.csproj" "Services/Services.Common/Services.Common.csproj"
COPY "Services/Contact/Contact.API/Contact.API.csproj" "Services/Contact/Contact.API/Contact.API.csproj"
COPY "Services/Webhooks/Webhooks.API/Webhooks.API.csproj" "Services/Webhooks/Webhooks.API/Webhooks.API.csproj"
COPY "Tests/Services/Application.FunctionalTests/Application.FunctionalTests.csproj" "Tests/Services/Application.FunctionalTests/Application.FunctionalTests.csproj"
COPY "Web/WebhookClient/WebhookClient.csproj" "Web/WebhookClient/WebhookClient.csproj"
@ -42,6 +43,7 @@ COPY "Web/WebStatus/WebStatus.csproj" "Web/WebStatus/WebStatus.csproj"
COPY "docker-compose.dcproj" "docker-compose.dcproj"
COPY "Directory.Packages.props" "Directory.Packages.props"
COPY "NuGet.config" "NuGet.config"
RUN dotnet restore "eShopOnContainers-ServicesAndWebApps.sln"

View File

@ -1,4 +1,4 @@
FROM mcr.microsoft.com/dotnet/sdk:6.0
FROM mcr.microsoft.com/dotnet/sdk:7.0
ARG BUILD_CONFIGURATION=Debug
ENV ASPNETCORE_ENVIRONMENT=Development
ENV DOTNET_USE_POLLING_FILE_WATCHER=true
@ -6,7 +6,6 @@ EXPOSE 80
WORKDIR /src
COPY ["src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj", "src/ApiGateways/Web.Bff.Shopping/aggregator/"]
COPY ["src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj", "src/BuildingBlocks/Devspaces.Support/"]
COPY ["src/NuGet.config", "src/NuGet.config"]
RUN dotnet restore src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj -nowarn:msb3202,nu1503

View File

@ -0,0 +1,63 @@
internal static class Extensions
{
public static IServiceCollection AddReverseProxy(this IServiceCollection services, IConfiguration configuration)
{
services.AddReverseProxy().LoadFromConfig(configuration.GetRequiredSection("ReverseProxy"));
return services;
}
public static IServiceCollection AddHealthChecks(this IServiceCollection services, IConfiguration configuration)
{
services.AddHealthChecks()
.AddUrlGroup(_ => new Uri(configuration.GetRequiredValue("CatalogUrlHC")), name: "catalogapi-check", tags: new string[] { "catalogapi" })
.AddUrlGroup(_ => new Uri(configuration.GetRequiredValue("OrderingUrlHC")), name: "orderingapi-check", tags: new string[] { "orderingapi" })
.AddUrlGroup(_ => new Uri(configuration.GetRequiredValue("BasketUrlHC")), name: "basketapi-check", tags: new string[] { "basketapi" })
.AddUrlGroup(_ => new Uri(configuration.GetRequiredValue("IdentityUrlHC")), name: "identityapi-check", tags: new string[] { "identityapi" });
return services;
}
public static IServiceCollection AddApplicationServices(this IServiceCollection services)
{
// Register delegating handlers
services.AddTransient<HttpClientAuthorizationDelegatingHandler>();
// Register http services
services.AddHttpClient<IOrderApiClient, OrderApiClient>()
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>();
return services;
}
public static IServiceCollection AddGrpcServices(this IServiceCollection services)
{
services.AddTransient<GrpcExceptionInterceptor>();
services.AddScoped<IBasketService, BasketService>();
services.AddGrpcClient<Basket.BasketClient>((services, options) =>
{
var basketApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcBasket;
options.Address = new Uri(basketApi);
}).AddInterceptor<GrpcExceptionInterceptor>();
services.AddScoped<ICatalogService, CatalogService>();
services.AddGrpcClient<Catalog.CatalogClient>((services, options) =>
{
var catalogApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcCatalog;
options.Address = new Uri(catalogApi);
}).AddInterceptor<GrpcExceptionInterceptor>();
services.AddScoped<IOrderingService, OrderingService>();
services.AddGrpcClient<GrpcOrdering.OrderingGrpc.OrderingGrpcClient>((services, options) =>
{
var orderingApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcOrdering;
options.Address = new Uri(orderingApi);
}).AddInterceptor<GrpcExceptionInterceptor>();
return services;
}
}

View File

@ -1,34 +0,0 @@
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Filters
{
namespace Basket.API.Infrastructure.Filters
{
public class AuthorizeCheckOperationFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
// Check for authorize attribute
var hasAuthorize = context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any() ||
context.MethodInfo.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any();
if (!hasAuthorize) return;
operation.Responses.TryAdd("401", new OpenApiResponse { Description = "Unauthorized" });
operation.Responses.TryAdd("403", new OpenApiResponse { Description = "Forbidden" });
var oAuthScheme = new OpenApiSecurityScheme
{
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" }
};
operation.Security = new List<OpenApiSecurityRequirement>
{
new()
{
[ oAuthScheme ] = new[] { "Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator" }
}
};
}
}
}
}

View File

@ -1,41 +1,13 @@
global using CatalogApi;
global using Devspaces.Support;
global using Grpc.Core.Interceptors;
global using System.Text.Json;
global using CatalogApi;
global using Grpc.Core;
global using Grpc.Core.Interceptors;
global using GrpcBasket;
global using GrpcOrdering;
global using HealthChecks.UI.Client;
global using Microsoft.AspNetCore.Authentication.JwtBearer;
global using Microsoft.AspNetCore.Authentication;
global using Microsoft.AspNetCore.Authorization;
global using Microsoft.AspNetCore.Builder;
global using Microsoft.AspNetCore.Diagnostics.HealthChecks;
global using Microsoft.AspNetCore.Hosting;
global using Microsoft.AspNetCore.Http;
global using Microsoft.AspNetCore.Mvc;
global using Microsoft.AspNetCore;
global using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config;
global using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Filters.Basket.API.Infrastructure.Filters;
global using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Infrastructure;
global using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models;
global using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services;
global using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator;
global using Microsoft.Extensions.Configuration;
global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.Diagnostics.HealthChecks;
global using Microsoft.Extensions.Hosting;
global using Microsoft.Extensions.Logging;
global using Microsoft.Extensions.Options;
global using Microsoft.OpenApi.Models;
global using Serilog;
global using Swashbuckle.AspNetCore.SwaggerGen;
global using System.Collections.Generic;
global using System.IdentityModel.Tokens.Jwt;
global using System.Linq;
global using System.Net.Http.Headers;
global using System.Net.Http;
global using System.Net;
global using System.Text.Json;
global using System.Threading.Tasks;
global using System.Threading;
global using System;
global using Services.Common;

View File

@ -28,7 +28,7 @@ public class GrpcExceptionInterceptor : Interceptor
}
catch (RpcException e)
{
_logger.LogError("Error calling via grpc: {Status} - {Message}", e.Status, e.Message);
_logger.LogError(e, "Error calling via gRPC: {Status}", e.Status);
return default;
}
}

View File

@ -1,40 +0,0 @@
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Infrastructure;
public class HttpClientAuthorizationDelegatingHandler
: DelegatingHandler
{
private readonly IHttpContextAccessor _httpContextAccessor;
public HttpClientAuthorizationDelegatingHandler(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var authorizationHeader = _httpContextAccessor.HttpContext
.Request.Headers["Authorization"];
if (!string.IsNullOrWhiteSpace(authorizationHeader))
{
request.Headers.Add("Authorization", new List<string>() { authorizationHeader });
}
var token = await GetTokenAsync();
if (token != null)
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
}
return await base.SendAsync(request, cancellationToken);
}
Task<string> GetTokenAsync()
{
const string ACCESS_TOKEN = "access_token";
return _httpContextAccessor.HttpContext
.GetTokenAsync(ACCESS_TOKEN);
}
}

View File

@ -1,24 +1,38 @@
await BuildWebHost(args).RunAsync();
var builder = WebApplication.CreateBuilder(args);
IWebHost BuildWebHost(string[] args) =>
WebHost
.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(cb =>
{
var sources = cb.Sources;
sources.Insert(3, new Microsoft.Extensions.Configuration.Json.JsonConfigurationSource()
{
Optional = true,
Path = "appsettings.localhost.json",
ReloadOnChange = false
});
})
.UseStartup<Startup>()
.UseSerilog((builderContext, config) =>
{
config
.MinimumLevel.Information()
.Enrich.FromLogContext()
.WriteTo.Console();
})
.Build();
builder.AddServiceDefaults();
builder.Services.AddReverseProxy(builder.Configuration);
builder.Services.AddControllers();
builder.Services.AddHealthChecks(builder.Configuration);
builder.Services.AddCors(options =>
{
// TODO: Read allowed origins from configuration
options.AddPolicy("CorsPolicy",
builder => builder
.SetIsOriginAllowed((host) => true)
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
builder.Services.AddApplicationServices();
builder.Services.AddGrpcServices();
builder.Services.Configure<UrlsConfig>(builder.Configuration.GetSection("urls"));
var app = builder.Build();
app.UseServiceDefaults();
app.UseHttpsRedirection();
app.UseCors("CorsPolicy");
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.MapReverseProxy();
await app.RunAsync();

View File

@ -1,29 +1,12 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:57425/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"Web.Shopping.HttpAggregator": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "api/values",
"applicationUrl": "http://localhost:5229/",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"PurchaseForMvc": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "api/values",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:61632/"
}
}
}

View File

@ -10,7 +10,7 @@ public class BasketService : IBasketService
_basketClient = basketClient;
_logger = logger;
}
public async Task<BasketData> GetByIdAsync(string id)
{
_logger.LogDebug("grpc client created, request = {@id}", id);

View File

@ -23,9 +23,6 @@ public class OrderApiClient : IOrderApiClient
var ordersDraftResponse = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<OrderData>(ordersDraftResponse, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
return JsonSerializer.Deserialize<OrderData>(ordersDraftResponse, JsonDefaults.CaseInsensitiveOptions);
}
}

View File

@ -2,10 +2,10 @@
public class OrderingService : IOrderingService
{
private readonly OrderingGrpc.OrderingGrpcClient _orderingGrpcClient;
private readonly GrpcOrdering.OrderingGrpc.OrderingGrpcClient _orderingGrpcClient;
private readonly ILogger<OrderingService> _logger;
public OrderingService(OrderingGrpc.OrderingGrpcClient orderingGrpcClient, ILogger<OrderingService> logger)
public OrderingService(GrpcOrdering.OrderingGrpc.OrderingGrpcClient orderingGrpcClient, ILogger<OrderingService> logger)
{
_orderingGrpcClient = orderingGrpcClient;
_logger = logger;
@ -48,14 +48,14 @@ public class OrderingService : IOrderingService
return data;
}
private CreateOrderDraftCommand MapToOrderDraftCommand(BasketData basketData)
private GrpcOrdering.CreateOrderDraftCommand MapToOrderDraftCommand(BasketData basketData)
{
var command = new CreateOrderDraftCommand
var command = new GrpcOrdering.CreateOrderDraftCommand
{
BuyerId = basketData.BuyerId,
};
basketData.Items.ForEach(i => command.Items.Add(new BasketItem
basketData.Items.ForEach(i => command.Items.Add(new GrpcOrdering.BasketItem
{
Id = i.Id,
OldUnitPrice = (double)i.OldUnitPrice,

View File

@ -1,199 +0,0 @@
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator;
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks()
.AddCheck("self", () => HealthCheckResult.Healthy())
.AddUrlGroup(new Uri(Configuration["CatalogUrlHC"]), name: "catalogapi-check", tags: new string[] { "catalogapi" })
.AddUrlGroup(new Uri(Configuration["OrderingUrlHC"]), name: "orderingapi-check", tags: new string[] { "orderingapi" })
.AddUrlGroup(new Uri(Configuration["BasketUrlHC"]), name: "basketapi-check", tags: new string[] { "basketapi" })
.AddUrlGroup(new Uri(Configuration["IdentityUrlHC"]), name: "identityapi-check", tags: new string[] { "identityapi" })
.AddUrlGroup(new Uri(Configuration["PaymentUrlHC"]), name: "paymentapi-check", tags: new string[] { "paymentapi" });
services.AddCustomMvc(Configuration)
.AddCustomAuthentication(Configuration)
.AddDevspaces()
.AddApplicationServices()
.AddGrpcServices();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
var pathBase = Configuration["PATH_BASE"];
if (!string.IsNullOrEmpty(pathBase))
{
loggerFactory.CreateLogger<Startup>().LogDebug("Using PATH BASE '{pathBase}'", pathBase);
app.UsePathBase(pathBase);
}
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseSwagger().UseSwaggerUI(c =>
{
c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1");
c.OAuthClientId("webshoppingaggswaggerui");
c.OAuthClientSecret(string.Empty);
c.OAuthRealm(string.Empty);
c.OAuthAppName("web shopping bff Swagger UI");
});
app.UseRouting();
app.UseCors("CorsPolicy");
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
endpoints.MapControllers();
endpoints.MapHealthChecks("/hc", new HealthCheckOptions()
{
Predicate = _ => true,
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
endpoints.MapHealthChecks("/liveness", new HealthCheckOptions
{
Predicate = r => r.Name.Contains("self")
});
});
}
}
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub");
var identityUrl = configuration.GetValue<string>("urls:identity");
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Authority = identityUrl;
options.RequireHttpsMetadata = false;
options.Audience = "webshoppingagg";
});
return services;
}
public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration)
{
services.AddOptions();
services.Configure<UrlsConfig>(configuration.GetSection("urls"));
services.AddControllers()
.AddJsonOptions(options => options.JsonSerializerOptions.WriteIndented = true);
services.AddSwaggerGen(options =>
{
options.DescribeAllEnumsAsStrings();
options.SwaggerDoc("v1", new OpenApiInfo
{
Title = "Shopping Aggregator for Web Clients",
Version = "v1",
Description = "Shopping Aggregator for Web Clients"
});
options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows()
{
Implicit = new OpenApiOAuthFlow()
{
AuthorizationUrl = new Uri($"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize"),
TokenUrl = new Uri($"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/token"),
Scopes = new Dictionary<string, string>()
{
{ "webshoppingagg", "Shopping Aggregator for Web Clients" }
}
}
}
});
options.OperationFilter<AuthorizeCheckOperationFilter>();
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder
.SetIsOriginAllowed((host) => true)
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
return services;
}
public static IServiceCollection AddApplicationServices(this IServiceCollection services)
{
//register delegating handlers
services.AddTransient<HttpClientAuthorizationDelegatingHandler>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
//register http services
services.AddHttpClient<IOrderApiClient, OrderApiClient>()
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>()
.AddDevspacesSupport();
return services;
}
public static IServiceCollection AddGrpcServices(this IServiceCollection services)
{
services.AddTransient<GrpcExceptionInterceptor>();
services.AddScoped<IBasketService, BasketService>();
services.AddGrpcClient<Basket.BasketClient>((services, options) =>
{
var basketApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcBasket;
options.Address = new Uri(basketApi);
}).AddInterceptor<GrpcExceptionInterceptor>();
services.AddScoped<ICatalogService, CatalogService>();
services.AddGrpcClient<Catalog.CatalogClient>((services, options) =>
{
var catalogApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcCatalog;
options.Address = new Uri(catalogApi);
}).AddInterceptor<GrpcExceptionInterceptor>();
services.AddScoped<IOrderingService, OrderingService>();
services.AddGrpcClient<OrderingGrpc.OrderingGrpcClient>((services, options) =>
{
var orderingApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcOrdering;
options.Address = new Uri(orderingApi);
}).AddInterceptor<GrpcExceptionInterceptor>();
return services;
}
}

View File

@ -1,37 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<AssemblyName>Web.Shopping.HttpAggregator</AssemblyName>
<RootNamespace>Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
<GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks>
<IsTransformWebConfigDisabled>true</IsTransformWebConfigDisabled>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
<PackageReference Include="Yarp.ReverseProxy" />
<PackageReference Include="AspNetCore.HealthChecks.Uris" />
<PackageReference Include="Google.Protobuf" />
<PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" />
<PackageReference Include="Grpc.Tools" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="5.0.1" />
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="5.0.1" />
<PackageReference Include="Google.Protobuf" Version="3.15.0" />
<PackageReference Include="Grpc.AspNetCore.Server.ClientFactory" Version="2.34.0" />
<PackageReference Include="Grpc.Core" Version="2.34.0" />
<PackageReference Include="Grpc.Net.Client" Version="2.34.0" />
<PackageReference Include="Grpc.Net.ClientFactory" Version="2.34.0" />
<PackageReference Include="Grpc.Tools" Version="2.34.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.9" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="5.0.2" />
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.0-dev-00834" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\Devspaces.Support\Devspaces.Support.csproj" />
<ProjectReference Include="..\..\..\Services\Services.Common\Services.Common.csproj" />
</ItemGroup>
<ItemGroup>

View File

@ -1,15 +1,8 @@
{
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Debug"
}
},
"Console": {
"LogLevel": {
"Default": "Debug"
}
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@ -1,15 +1,138 @@
{
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"System.Net.Http": "Warning"
}
},
"OpenApi": {
"Endpoint": {
"Name": "Purchase BFF V1"
},
"Document": {
"Description": "Shopping Aggregator for Web Clients",
"Title": "Shopping Aggregator for Web Clients",
"Version": "v1"
},
"Auth": {
"ClientId": "webshoppingaggswaggerui",
"AppName": "Web Shopping BFF Swagger UI"
}
},
"Identity": {
"Url": "http://localhost:5223",
"Audience": "webshoppingagg",
"Scopes": {
"webshoppingagg": "Shopping Aggregator for Web Clients"
}
},
"ReverseProxy": {
"Routes": {
"c-short": {
"ClusterId": "catalog",
"Match": {
"Path": "c/{**catch-all}"
},
"Transforms": [
{ "PathRemovePrefix": "/c" }
]
},
"c-long": {
"ClusterId": "catalog",
"Match": {
"Path": "catalog-api/{**catch-all}"
},
"Transforms": [
{ "PathRemovePrefix": "/catalog-api" }
]
},
"b-short": {
"ClusterId": "basket",
"Match": {
"Path": "b/{**catch-all}"
},
"Transforms": [
{ "PathRemovePrefix": "/b" }
]
},
"b-long": {
"ClusterId": "basket",
"Match": {
"Path": "basket-api/{**catch-all}"
},
"Transforms": [
{ "PathRemovePrefix": "/basket-api" }
]
},
"o-short": {
"ClusterId": "orders",
"Match": {
"Path": "o/{**catch-all}"
},
"Transforms": [
{ "PathRemovePrefix": "/o" }
]
},
"o-long": {
"ClusterId": "orders",
"Match": {
"Path": "ordering-api/{**catch-all}"
},
"Transforms": [
{ "PathRemovePrefix": "/ordering-api" }
]
},
"h-long": {
"ClusterId": "signalr",
"Match": {
"Path": "hub/notificationhub/{**catch-all}"
}
}
},
"Console": {
"LogLevel": {
"Default": "Warning"
"Clusters": {
"basket": {
"Destinations": {
"destination0": {
"Address": "http://localhost:5221"
}
}
},
"catalog": {
"Destinations": {
"destination0": {
"Address": "http://localhost:5222"
}
}
},
"orders": {
"Destinations": {
"destination0": {
"Address": "http://localhost:5224"
}
}
},
"signalr": {
"Destinations": {
"destination0": {
"Address": "http://localhost:5225"
}
}
}
}
}
},
"Urls": {
"Basket": "http://localhost:5221",
"Catalog": "http://localhost:5222",
"Orders": "http://localhost:5224",
"Identity": "http://localhost:5223",
"Signalr": "http://localhost:5225",
"GrpcBasket": "http://localhost:6221",
"GrpcCatalog": "http://localhost:6222",
"GrpcOrdering": "http://localhost:6224"
},
"CatalogUrlHC": "http://localhost:5222/hc",
"OrderingUrlHC": "http://localhost:5224/hc",
"BasketUrlHC": "http://localhost:5221/hc",
"IdentityUrlHC": "http://localhost:5223/hc"
}

View File

@ -1,11 +0,0 @@
{
"urls": {
"basket": "http://localhost:55103",
"catalog": "http://localhost:55101",
"orders": "http://localhost:55102",
"identity": "http://localhost:55105",
"grpcBasket": "http://localhost:5580",
"grpcCatalog": "http://localhost:81",
"grpcOrdering": "http://localhost:5581"
}
}

View File

@ -1,55 +0,0 @@
kind: helm-release
apiVersion: 1.1
build:
context: ..\..\..\..
dockerfile: Dockerfile
install:
chart: ../../../../k8s/helm/webshoppingagg
set:
image:
tag: $(tag)
pullPolicy: Never
ingress:
annotations:
kubernetes.io/ingress.class: traefik-azds
hosts:
# This expands to [space.s.]apigwms.<guid>.<region>.aksapp.io
- $(spacePrefix)eshop$(hostSuffix)
inf:
k8s:
dns: $(spacePrefix)eshop$(hostSuffix)
values:
- values.dev.yaml?
- secrets.dev.yaml?
- app.yaml
- inf.yaml
configurations:
develop:
build:
useGitIgnore: true
dockerfile: Dockerfile.develop
container:
syncTarget: /src
sync:
- '**/Pages/**'
- '**/Views/**'
- '**/wwwroot/**'
- '!**/*.{sln,csproj}'
command:
- dotnet
- run
- --no-restore
- --no-build
- --no-launch-profile
- -c
- ${Configuration:-Debug}
iterate:
processesToKill:
- dotnet
- vsdbg
buildCommands:
- - dotnet
- build
- --no-restore
- -c
- ${Configuration:-Debug}

View File

@ -1,11 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
</ItemGroup>
</Project>

View File

@ -1,22 +0,0 @@
namespace Devspaces.Support;
public class DevspacesMessageHandler : DelegatingHandler
{
private const string DevspacesHeaderName = "azds-route-as";
private readonly IHttpContextAccessor _httpContextAccessor;
public DevspacesMessageHandler(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var req = _httpContextAccessor.HttpContext.Request;
if (req.Headers.ContainsKey(DevspacesHeaderName))
{
request.Headers.Add(DevspacesHeaderName, req.Headers[DevspacesHeaderName] as IEnumerable<string>);
}
return base.SendAsync(request, cancellationToken);
}
}

View File

@ -1,6 +0,0 @@
global using Microsoft.AspNetCore.Http;
global using Microsoft.Extensions.DependencyInjection;
global using System.Collections.Generic;
global using System.Net.Http;
global using System.Threading.Tasks;
global using System.Threading;

View File

@ -1,10 +0,0 @@
namespace Devspaces.Support;
public static class HttpClientBuilderDevspacesExtensions
{
public static IHttpClientBuilder AddDevspacesSupport(this IHttpClientBuilder builder)
{
builder.AddHttpMessageHandler<DevspacesMessageHandler>();
return builder;
}
}

View File

@ -1,10 +0,0 @@
namespace Devspaces.Support;
public static class ServiceCollectionDevspacesExtensions
{
public static IServiceCollection AddDevspaces(this IServiceCollection services)
{
services.AddTransient<DevspacesMessageHandler>();
return services;
}
}

View File

@ -1,16 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<IsPublishable>false</IsPublishable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="xunit.runner.visualstudio">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit" />
</ItemGroup>
<ItemGroup>

View File

@ -1,5 +1,4 @@
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus;
using System;
using System.Linq;
using Xunit;
@ -18,7 +17,7 @@ namespace EventBus.Tests
public void After_One_Event_Subscription_Should_Contain_The_Event()
{
var manager = new InMemoryEventBusSubscriptionsManager();
manager.AddSubscription<TestIntegrationEvent,TestIntegrationEventHandler>();
manager.AddSubscription<TestIntegrationEvent, TestIntegrationEventHandler>();
Assert.True(manager.HasSubscriptionsForEvent<TestIntegrationEvent>());
}

View File

@ -1,7 +1,4 @@
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
using System;
using System.Collections.Generic;
using System.Text;
namespace EventBus.Tests
{

View File

@ -1,7 +1,4 @@
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace EventBus.Tests
@ -15,9 +12,10 @@ namespace EventBus.Tests
Handled = false;
}
public async Task Handle(TestIntegrationEvent @event)
public Task Handle(TestIntegrationEvent @event)
{
Handled = true;
return Task.CompletedTask;
}
}
}

View File

@ -1,7 +1,4 @@
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace EventBus.Tests
@ -15,9 +12,10 @@ namespace EventBus.Tests
Handled = false;
}
public async Task Handle(TestIntegrationEvent @event)
public Task Handle(TestIntegrationEvent @event)
{
Handled = true;
return Task.CompletedTask;
}
}
}

View File

@ -8,12 +8,6 @@ public interface IEventBus
where T : IntegrationEvent
where TH : IIntegrationEventHandler<T>;
void SubscribeDynamic<TH>(string eventName)
where TH : IDynamicIntegrationEventHandler;
void UnsubscribeDynamic<TH>(string eventName)
where TH : IDynamicIntegrationEventHandler;
void Unsubscribe<T, TH>()
where TH : IIntegrationEventHandler<T>
where T : IntegrationEvent;

View File

@ -1,7 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.EventBus</RootNamespace>
</PropertyGroup>

View File

@ -1,7 +1,7 @@
namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
public record IntegrationEvent
{
{
public IntegrationEvent()
{
Id = Guid.NewGuid();

View File

@ -1,8 +1,4 @@
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
global using System.Text.Json.Serialization;
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
global using static Microsoft.eShopOnContainers.BuildingBlocks.EventBus.InMemoryEventBusSubscriptionsManager;
global using System.Collections.Generic;
global using System.Linq;
global using System.Text.Json.Serialization;
global using System.Threading.Tasks;
global using System;

View File

@ -59,7 +59,7 @@ public class DefaultRabbitMQPersistentConnection
.Or<BrokerUnreachableException>()
.WaitAndRetry(_retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) =>
{
_logger.LogWarning(ex, "RabbitMQ Client could not connect after {TimeOut}s ({ExceptionMessage})", $"{time.TotalSeconds:n1}", ex.Message);
_logger.LogWarning(ex, "RabbitMQ Client could not connect after {TimeOut}s", $"{time.TotalSeconds:n1}");
}
);
@ -81,7 +81,7 @@ public class DefaultRabbitMQPersistentConnection
}
else
{
_logger.LogCritical("FATAL ERROR: RabbitMQ connections could not be created and opened");
_logger.LogCritical("Fatal error: RabbitMQ connections could not be created and opened");
return false;
}

View File

@ -1,28 +1,31 @@
namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ;
using Microsoft.Extensions.DependencyInjection;
public class EventBusRabbitMQ : IEventBus, IDisposable
{
const string BROKER_NAME = "eshop_event_bus";
const string AUTOFAC_SCOPE_NAME = "eshop_event_bus";
private static readonly JsonSerializerOptions s_indentedOptions = new() { WriteIndented = true };
private static readonly JsonSerializerOptions s_caseInsensitiveOptions = new() { PropertyNameCaseInsensitive = true };
private readonly IRabbitMQPersistentConnection _persistentConnection;
private readonly ILogger<EventBusRabbitMQ> _logger;
private readonly IEventBusSubscriptionsManager _subsManager;
private readonly ILifetimeScope _autofac;
private readonly IServiceProvider _serviceProvider;
private readonly int _retryCount;
private IModel _consumerChannel;
private string _queueName;
public EventBusRabbitMQ(IRabbitMQPersistentConnection persistentConnection, ILogger<EventBusRabbitMQ> logger,
ILifetimeScope autofac, IEventBusSubscriptionsManager subsManager, string queueName = null, int retryCount = 5)
IServiceProvider serviceProvider, IEventBusSubscriptionsManager subsManager, string queueName = null, int retryCount = 5)
{
_persistentConnection = persistentConnection ?? throw new ArgumentNullException(nameof(persistentConnection));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_subsManager = subsManager ?? new InMemoryEventBusSubscriptionsManager();
_queueName = queueName;
_consumerChannel = CreateConsumerChannel();
_autofac = autofac;
_serviceProvider = serviceProvider;
_retryCount = retryCount;
_subsManager.OnEventRemoved += SubsManager_OnEventRemoved;
}
@ -57,7 +60,7 @@ public class EventBusRabbitMQ : IEventBus, IDisposable
.Or<SocketException>()
.WaitAndRetry(_retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) =>
{
_logger.LogWarning(ex, "Could not publish event: {EventId} after {Timeout}s ({ExceptionMessage})", @event.Id, $"{time.TotalSeconds:n1}", ex.Message);
_logger.LogWarning(ex, "Could not publish event: {EventId} after {Timeout}s", @event.Id, $"{time.TotalSeconds:n1}");
});
var eventName = @event.GetType().Name;
@ -69,17 +72,14 @@ public class EventBusRabbitMQ : IEventBus, IDisposable
channel.ExchangeDeclare(exchange: BROKER_NAME, type: "direct");
var body = JsonSerializer.SerializeToUtf8Bytes(@event, @event.GetType(), new JsonSerializerOptions
{
WriteIndented = true
});
var body = JsonSerializer.SerializeToUtf8Bytes(@event, @event.GetType(), s_indentedOptions);
policy.Execute(() =>
{
var properties = channel.CreateBasicProperties();
properties.DeliveryMode = 2; // persistent
_logger.LogTrace("Publishing event to RabbitMQ: {EventId}", @event.Id);
_logger.LogTrace("Publishing event to RabbitMQ: {EventId}", @event.Id);
channel.BasicPublish(
exchange: BROKER_NAME,
@ -122,7 +122,7 @@ public class EventBusRabbitMQ : IEventBus, IDisposable
{
_persistentConnection.TryConnect();
}
_consumerChannel.QueueBind(queue: _queueName,
exchange: BROKER_NAME,
routingKey: eventName);
@ -193,7 +193,7 @@ public class EventBusRabbitMQ : IEventBus, IDisposable
}
catch (Exception ex)
{
_logger.LogWarning(ex, "----- ERROR Processing message \"{Message}\"", message);
_logger.LogWarning(ex, "Error Processing message \"{Message}\"", message);
}
// Even on exception we take the message off the queue.
@ -240,23 +240,23 @@ public class EventBusRabbitMQ : IEventBus, IDisposable
if (_subsManager.HasSubscriptionsForEvent(eventName))
{
await using var scope = _autofac.BeginLifetimeScope(AUTOFAC_SCOPE_NAME);
await using var scope = _serviceProvider.CreateAsyncScope();
var subscriptions = _subsManager.GetHandlersForEvent(eventName);
foreach (var subscription in subscriptions)
{
if (subscription.IsDynamic)
{
if (scope.ResolveOptional(subscription.HandlerType) is not IDynamicIntegrationEventHandler handler) continue;
if (scope.ServiceProvider.GetService(subscription.HandlerType) is not IDynamicIntegrationEventHandler handler) continue;
using dynamic eventData = JsonDocument.Parse(message);
await Task.Yield();
await handler.Handle(eventData);
}
else
{
var handler = scope.ResolveOptional(subscription.HandlerType);
var handler = scope.ServiceProvider.GetService(subscription.HandlerType);
if (handler == null) continue;
var eventType = _subsManager.GetEventTypeByName(eventName);
var integrationEvent = JsonSerializer.Deserialize(message, eventType, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
var integrationEvent = JsonSerializer.Deserialize(message, eventType, s_caseInsensitiveOptions);
var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType);
await Task.Yield();

View File

@ -1,16 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Autofac" Version="6.1.0" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
<PackageReference Include="Polly" Version="7.2.1" />
<PackageReference Include="RabbitMQ.Client" Version="6.2.1" />
<PackageReference Include="Microsoft.CSharp" />
<PackageReference Include="Microsoft.Extensions.Logging" />
<PackageReference Include="Polly" />
<PackageReference Include="RabbitMQ.Client" />
</ItemGroup>
<ItemGroup>

View File

@ -1,17 +1,13 @@
global using Microsoft.Extensions.Logging;
global using System.Net.Sockets;
global using System.Text;
global using System.Text.Json;
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus;
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Extensions;
global using Microsoft.Extensions.Logging;
global using Polly;
global using Polly.Retry;
global using RabbitMQ.Client;
global using RabbitMQ.Client.Events;
global using RabbitMQ.Client.Exceptions;
global using System;
global using System.IO;
global using System.Net.Sockets;
global using Autofac;
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus;
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Extensions;
global using System.Text;
global using System.Threading.Tasks;
global using System.Text.Json;

View File

@ -27,7 +27,7 @@ public class DefaultServiceBusPersisterConnection : IServiceBusPersisterConnecti
}
}
public ServiceBusAdministrationClient AdministrationClient =>
public ServiceBusAdministrationClient AdministrationClient =>
_subscriptionClient;
public ServiceBusClient CreateModel()

View File

@ -1,3 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus;
public class EventBusServiceBus : IEventBus, IAsyncDisposable
@ -5,21 +7,20 @@ public class EventBusServiceBus : IEventBus, IAsyncDisposable
private readonly IServiceBusPersisterConnection _serviceBusPersisterConnection;
private readonly ILogger<EventBusServiceBus> _logger;
private readonly IEventBusSubscriptionsManager _subsManager;
private readonly ILifetimeScope _autofac;
private readonly IServiceProvider _serviceProvider;
private readonly string _topicName = "eshop_event_bus";
private readonly string _subscriptionName;
private readonly ServiceBusSender _sender;
private readonly ServiceBusProcessor _processor;
private readonly string AUTOFAC_SCOPE_NAME = "eshop_event_bus";
private const string INTEGRATION_EVENT_SUFFIX = "IntegrationEvent";
public EventBusServiceBus(IServiceBusPersisterConnection serviceBusPersisterConnection,
ILogger<EventBusServiceBus> logger, IEventBusSubscriptionsManager subsManager, ILifetimeScope autofac, string subscriptionClientName)
ILogger<EventBusServiceBus> logger, IEventBusSubscriptionsManager subsManager, IServiceProvider serviceProvider, string subscriptionClientName)
{
_serviceBusPersisterConnection = serviceBusPersisterConnection;
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_subsManager = subsManager ?? new InMemoryEventBusSubscriptionsManager();
_autofac = autofac;
_serviceProvider = serviceProvider;
_subscriptionName = subscriptionClientName;
_sender = _serviceBusPersisterConnection.TopicClient.CreateSender(_topicName);
ServiceBusProcessorOptions options = new ServiceBusProcessorOptions { MaxConcurrentCalls = 10, AutoCompleteMessages = false };
@ -139,7 +140,7 @@ public class EventBusServiceBus : IEventBus, IAsyncDisposable
var ex = args.Exception;
var context = args.ErrorSource;
_logger.LogError(ex, "ERROR handling message: {ExceptionMessage} - Context: {@ExceptionContext}", ex.Message, context);
_logger.LogError(ex, "Error handling message - Context: {@ExceptionContext}", context);
return Task.CompletedTask;
}
@ -149,20 +150,20 @@ public class EventBusServiceBus : IEventBus, IAsyncDisposable
var processed = false;
if (_subsManager.HasSubscriptionsForEvent(eventName))
{
var scope = _autofac.BeginLifetimeScope(AUTOFAC_SCOPE_NAME);
await using var scope = _serviceProvider.CreateAsyncScope();
var subscriptions = _subsManager.GetHandlersForEvent(eventName);
foreach (var subscription in subscriptions)
{
if (subscription.IsDynamic)
{
if (scope.ResolveOptional(subscription.HandlerType) is not IDynamicIntegrationEventHandler handler) continue;
if (scope.ServiceProvider.GetService(subscription.HandlerType) is not IDynamicIntegrationEventHandler handler) continue;
using dynamic eventData = JsonDocument.Parse(message);
await handler.Handle(eventData);
}
else
{
var handler = scope.ResolveOptional(subscription.HandlerType);
var handler = scope.ServiceProvider.GetService(subscription.HandlerType);
if (handler == null) continue;
var eventType = _subsManager.GetEventTypeByName(eventName);
var integrationEvent = JsonSerializer.Deserialize(message, eventType);
@ -196,4 +197,4 @@ public class EventBusServiceBus : IEventBus, IAsyncDisposable
_subsManager.Clear();
await _processor.CloseAsync();
}
}
}

View File

@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Autofac" Version="6.1.0" />
<PackageReference Include="Azure.Messaging.ServiceBus" Version="7.2.1" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
<PackageReference Include="Azure.Messaging.ServiceBus" />
<PackageReference Include="Microsoft.CSharp" />
<PackageReference Include="Microsoft.Extensions.Logging" />
</ItemGroup>
<ItemGroup>

View File

@ -1,19 +1,11 @@
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
global using static Microsoft.eShopOnContainers.BuildingBlocks.EventBus.InMemoryEventBusSubscriptionsManager;
global using System.Collections.Generic;
global using System.Linq;
global using System.Text.Json.Serialization;
global using System.Threading.Tasks;
global using System;
global using Autofac;
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus;
global using Microsoft.Extensions.Logging;
global using System.Text;
global using System.Text;
global using System.Text.Json;
global using Azure.Messaging.ServiceBus;
global using Azure.Messaging.ServiceBus.Administration;
global using System;
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus;
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
global using Microsoft.Extensions.Logging;

View File

@ -1,12 +1,8 @@
global using Microsoft.EntityFrameworkCore;
global using Microsoft.EntityFrameworkCore.Metadata.Builders;
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
global using System;
global using System.Text.Json;
global using System.ComponentModel.DataAnnotations.Schema;
global using System.Linq;
global using System.Threading.Tasks;
global using Microsoft.EntityFrameworkCore.Storage;
global using System.Collections.Generic;
global using System.ComponentModel.DataAnnotations.Schema;
global using System.Data.Common;
global using System.Reflection;
global using System.Text.Json;
global using Microsoft.EntityFrameworkCore;
global using Microsoft.EntityFrameworkCore.Metadata.Builders;
global using Microsoft.EntityFrameworkCore.Storage;
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;

View File

@ -1,18 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.0">
<PackageReference Include="Microsoft.EntityFrameworkCore.Design">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" />
<PackageReference Include="Microsoft.EntityFrameworkCore" />
</ItemGroup>
<ItemGroup>

View File

@ -2,16 +2,16 @@
public class IntegrationEventLogEntry
{
private static readonly JsonSerializerOptions s_indentedOptions = new() { WriteIndented = true };
private static readonly JsonSerializerOptions s_caseInsensitiveOptions = new() { PropertyNameCaseInsensitive = true };
private IntegrationEventLogEntry() { }
public IntegrationEventLogEntry(IntegrationEvent @event, Guid transactionId)
{
EventId = @event.Id;
CreationTime = @event.CreationDate;
EventTypeName = @event.GetType().FullName;
Content = JsonSerializer.Serialize(@event, @event.GetType(), new JsonSerializerOptions
{
WriteIndented = true
});
EventTypeName = @event.GetType().FullName;
Content = JsonSerializer.Serialize(@event, @event.GetType(), s_indentedOptions);
State = EventStateEnum.NotPublished;
TimesSent = 0;
TransactionId = transactionId.ToString();
@ -29,8 +29,8 @@ public class IntegrationEventLogEntry
public string TransactionId { get; private set; }
public IntegrationEventLogEntry DeserializeJsonContent(Type type)
{
IntegrationEvent = JsonSerializer.Deserialize(Content, type, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true }) as IntegrationEvent;
{
IntegrationEvent = JsonSerializer.Deserialize(Content, type, s_caseInsensitiveOptions) as IntegrationEvent;
return this;
}
}

View File

@ -1,26 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="5.0.0" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="5.0.0" />
<PackageReference Include="Polly" Version="7.2.1" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.2" />
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" />
<PackageReference Include="Polly" />
<PackageReference Include="System.Data.SqlClient" />
</ItemGroup>
</Project>

View File

@ -1,77 +1,75 @@
using Microsoft.EntityFrameworkCore;
using System.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Polly;
using System;
using System.Data.SqlClient;
namespace Microsoft.AspNetCore.Hosting
namespace Microsoft.AspNetCore.Hosting;
public static class IWebHostExtensions
{
public static class IWebHostExtensions
public static bool IsInKubernetes(this IServiceProvider services)
{
public static bool IsInKubernetes(this IWebHost webHost)
var cfg = services.GetService<IConfiguration>();
var orchestratorType = cfg.GetValue<string>("OrchestratorType");
return orchestratorType?.ToUpper() == "K8S";
}
public static IServiceProvider MigrateDbContext<TContext>(this IServiceProvider services, Action<TContext, IServiceProvider> seeder) where TContext : DbContext
{
var underK8s = services.IsInKubernetes();
using var scope = services.CreateScope();
var scopeServices = scope.ServiceProvider;
var logger = scopeServices.GetRequiredService<ILogger<TContext>>();
var context = scopeServices.GetService<TContext>();
try
{
var cfg = webHost.Services.GetService<IConfiguration>();
var orchestratorType = cfg.GetValue<string>("OrchestratorType");
return orchestratorType?.ToUpper() == "K8S";
}
logger.LogInformation("Migrating database associated with context {DbContextName}", typeof(TContext).Name);
public static IWebHost MigrateDbContext<TContext>(this IWebHost webHost, Action<TContext, IServiceProvider> seeder) where TContext : DbContext
{
var underK8s = webHost.IsInKubernetes();
using var scope = webHost.Services.CreateScope();
var services = scope.ServiceProvider;
var logger = services.GetRequiredService<ILogger<TContext>>();
var context = services.GetService<TContext>();
try
if (underK8s)
{
logger.LogInformation("Migrating database associated with context {DbContextName}", typeof(TContext).Name);
if (underK8s)
{
InvokeSeeder(seeder, context, services);
}
else
{
var retries = 10;
var retry = Policy.Handle<SqlException>()
.WaitAndRetry(
retryCount: retries,
sleepDurationProvider: retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
onRetry: (exception, timeSpan, retry, ctx) =>
{
logger.LogWarning(exception, "[{prefix}] Exception {ExceptionType} with message {Message} detected on attempt {retry} of {retries}", nameof(TContext), exception.GetType().Name, exception.Message, retry, retries);
});
//if the sql server container is not created on run docker compose this
//migration can't fail for network related exception. The retry options for DbContext only
//apply to transient exceptions
// Note that this is NOT applied when running some orchestrators (let the orchestrator to recreate the failing service)
retry.Execute(() => InvokeSeeder(seeder, context, services));
}
logger.LogInformation("Migrated database associated with context {DbContextName}", typeof(TContext).Name);
InvokeSeeder(seeder, context, scopeServices);
}
catch (Exception ex)
else
{
logger.LogError(ex, "An error occurred while migrating the database used on context {DbContextName}", typeof(TContext).Name);
if (underK8s)
{
throw; // Rethrow under k8s because we rely on k8s to re-run the pod
}
var retries = 10;
var retry = Policy.Handle<SqlException>()
.WaitAndRetry(
retryCount: retries,
sleepDurationProvider: retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
onRetry: (exception, timeSpan, retry, ctx) =>
{
logger.LogWarning(exception, "[{prefix}] Error migrating database (attempt {retry} of {retries})", nameof(TContext), retry, retries);
});
//if the sql server container is not created on run docker compose this
//migration can't fail for network related exception. The retry options for DbContext only
//apply to transient exceptions
// Note that this is NOT applied when running some orchestrators (let the orchestrator to recreate the failing service)
retry.Execute(() => InvokeSeeder(seeder, context, scopeServices));
}
return webHost;
logger.LogInformation("Migrated database associated with context {DbContextName}", typeof(TContext).Name);
}
catch (Exception ex)
{
logger.LogError(ex, "An error occurred while migrating the database used on context {DbContextName}", typeof(TContext).Name);
if (underK8s)
{
throw; // Rethrow under k8s because we rely on k8s to re-run the pod
}
}
private static void InvokeSeeder<TContext>(Action<TContext, IServiceProvider> seeder, TContext context, IServiceProvider services)
where TContext : DbContext
{
context.Database.Migrate();
seeder(context, services);
}
return services;
}
private static void InvokeSeeder<TContext>(Action<TContext, IServiceProvider> seeder, TContext context, IServiceProvider services)
where TContext : DbContext
{
context.Database.Migrate();
seeder(context, services);
}
}

View File

@ -0,0 +1,93 @@
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="AspNetCore.HealthChecks.AzureServiceBus" Version="6.1.0" />
<PackageVersion Include="AspNetCore.HealthChecks.AzureStorage" Version="6.1.2" />
<PackageVersion Include="AspNetCore.HealthChecks.Rabbitmq" Version="6.0.2" />
<PackageVersion Include="AspNetCore.HealthChecks.Redis" Version="6.0.4" />
<PackageVersion Include="AspNetCore.HealthChecks.SqlServer" Version="6.0.2" />
<PackageVersion Include="AspNetCore.HealthChecks.UI" Version="6.0.5" />
<PackageVersion Include="AspNetCore.HealthChecks.UI.Client" Version="6.0.5" />
<PackageVersion Include="AspNetCore.HealthChecks.UI.InMemory.Storage" Version="6.0.5" />
<PackageVersion Include="AspNetCore.HealthChecks.Uris" Version="6.0.3" />
<PackageVersion Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.2.2" />
<PackageVersion Include="Azure.Identity" Version="1.8.2" />
<PackageVersion Include="Azure.Messaging.ServiceBus" Version="7.12.0" />
<PackageVersion Include="BuildBundlerMinifier" Version="3.2.449" />
<PackageVersion Include="Dapper" Version="2.0.123" />
<PackageVersion Include="Duende.IdentityServer" Version="6.2.3" />
<PackageVersion Include="Duende.IdentityServer.AspNetIdentity" Version="6.2.3" />
<PackageVersion Include="Duende.IdentityServer.EntityFramework" Version="6.2.3" />
<PackageVersion Include="Duende.IdentityServer.EntityFramework.Storage" Version="6.2.3" />
<PackageVersion Include="Duende.IdentityServer.Storage" Version="6.2.3" />
<PackageVersion Include="FluentValidation.AspNetCore" Version="11.2.2" />
<PackageVersion Include="Google.Protobuf" Version="3.22.0" />
<PackageVersion Include="Grpc.AspNetCore.Server" Version="2.51.0" />
<PackageVersion Include="Grpc.AspNetCore" Version="2.51.0" />
<PackageVersion Include="Grpc.AspNetCore.Server.ClientFactory" Version="2.51.0" />
<PackageVersion Include="Grpc.Core" Version="2.46.6" />
<PackageVersion Include="Grpc.Net.Client" Version="2.51.0" />
<PackageVersion Include="Grpc.Net.ClientFactory" Version="2.51.0" />
<PackageVersion Include="Grpc.Tools" Version="2.51.0" PrivateAssets="All" />
<PackageVersion Include="MediatR" Version="12.0.0" />
<PackageVersion Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.22.0-beta1" />
<PackageVersion Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.22.0-beta1" />
<PackageVersion Include="Microsoft.ApplicationInsights.Kubernetes" Version="6.0.0" />
<PackageVersion Include="Microsoft.AspNet.WebApi.Client" Version="5.2.9" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.3" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="7.0.3" />
<PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="7.0.3" />
<PackageVersion Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="7.0.3" />
<PackageVersion Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="7.0.3" />
<PackageVersion Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
<PackageVersion Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
<PackageVersion Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.3" />
<PackageVersion Include="Microsoft.AspNetCore.Identity.UI" Version="7.0.3" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="7.0.3" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="7.0.3" />
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="7.0.5" />
<PackageVersion Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="7.0.3" />
<PackageVersion Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="7.0.3" />
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="7.0.3" />
<PackageVersion Include="Microsoft.Build.Utilities.Core" Version="17.4.0" />
<PackageVersion Include="Microsoft.CSharp" Version="4.7.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="7.0.3" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.3" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.3" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.3" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.3" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.3" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.3" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.3" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyModel" Version="7.0.0" />
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="7.0.3" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="7.0.0" />
<PackageVersion Include="Microsoft.Extensions.Identity.Stores" Version="7.0.3" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="7.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.AzureAppServices" Version="7.0.3" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageVersion Include="Microsoft.NETCore.Platforms" Version="7.0.0" />
<PackageVersion Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.18.1" />
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.4" />
<PackageVersion Include="Microsoft.Web.LibraryManager.Build" Version="2.1.175" />
<PackageVersion Include="Moq" Version="4.18.4" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.2" />
<PackageVersion Include="Polly" Version="7.2.3" />
<PackageVersion Include="RabbitMQ.Client" Version="6.4.0" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageVersion Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.5.0" />
<PackageVersion Include="System.Data.SqlClient" Version="4.8.5" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.27.0" />
<PackageVersion Include="System.Reflection.TypeExtensions" Version="4.7.0" />
<PackageVersion Include="xunit" Version="2.4.2" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.4.5" />
<PackageVersion Include="Yarp.ReverseProxy" Version="2.0.0" />
</ItemGroup>
</Project>

View File

@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<config>
<add key="repositoryPath" value="packages" />
</config>
<packageSources>
<add key="NuGet" value="https://api.nuget.org/v3/index.json" />
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
</packageSources>
</configuration>
<solution>
<add key="disableSourceControlIntegration" value="true" />
</solution>
</configuration>

View File

@ -1,28 +0,0 @@
(function ($, swaggerUi) {
$(function () {
var settings = {
authority: 'https://localhost:5105',
client_id: 'js',
popup_redirect_uri: window.location.protocol
+ '//'
+ window.location.host
+ '/tokenclient/popup.html',
response_type: 'id_token token',
scope: 'openid profile basket',
filter_protocol_claims: true
},
manager = new OidcTokenManager(settings),
$inputApiKey = $('#input_apiKey');
$inputApiKey.on('dblclick', function () {
manager.openPopupForTokenAsync()
.then(function () {
$inputApiKey.val(manager.access_token).change();
}, function (error) {
console.error(error);
});
});
});
})(jQuery, window.swaggerUi);

File diff suppressed because one or more lines are too long

View File

@ -1,13 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />
</head>
<body>
<script type="text/javascript" src="oidc-token-manager.min.js"></script>
<script type="text/javascript">
new OidcTokenManager().processTokenPopup();
</script>
</body>
</html>

View File

@ -1,25 +0,0 @@
namespace Microsoft.eShopOnContainers.Services.Basket.API.Auth.Server;
public class AuthorizationHeaderParameterOperationFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var filterPipeline = context.ApiDescription.ActionDescriptor.FilterDescriptors;
var isAuthorized = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is AuthorizeFilter);
var allowAnonymous = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is IAllowAnonymousFilter);
if (isAuthorized && !allowAnonymous)
{
operation.Parameters ??= new List<OpenApiParameter>();
operation.Parameters.Add(new OpenApiParameter
{
Name = "Authorization",
In = ParameterLocation.Header,
Description = "access token",
Required = true
});
}
}
}

View File

@ -1,60 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<DockerComposeProjectPath>..\..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
<GenerateErrorForMissingTargetingPacks>false</GenerateErrorForMissingTargetingPacks>
<IsTransformWebConfigDisabled>true</IsTransformWebConfigDisabled>
<UserSecretsId>2964ec8e-0d48-4541-b305-94cab537f867</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<Content Update="web.config">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.12.2" />
<PackageReference Include="Azure.Identity" Version="1.5.0-beta.3" />
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="5.1.1" />
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="5.0.1" />
<PackageReference Include="AspNetCore.HealthChecks.Redis" Version="5.0.2" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="5.0.1" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.2.0-preview.1" />
<PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.2.1" />
<PackageReference Include="Azure.Identity" Version="1.4.0" />
<PackageReference Include="Google.Protobuf" Version="3.15.0" />
<PackageReference Include="Grpc.AspNetCore.Server" Version="2.34.0" />
<PackageReference Include="Grpc.Tools" Version="2.34.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.18.0" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.18.0" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="2.0.2-beta2" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.18" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="6.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.11.1" />
<PackageReference Include="Serilog.AspNetCore" Version="4.1.1-dev-00229" />
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.2.1-dev-00787" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.3.0-dev-00291" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1-dev-00876" />
<PackageReference Include="Serilog.Sinks.Http" Version="8.0.0-beta.9" />
<PackageReference Include="Serilog.Sinks.Seq" Version="4.1.0-dev-00166" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.1" />
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.2.1" />
<PackageReference Include="Grpc.AspNetCore" />
<PackageReference Include="AspNetCore.HealthChecks.Redis" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" />
</ItemGroup>
<ItemGroup>
<Protobuf Include="Proto\basket.proto" GrpcServices="Server" Generator="MSBuild:Compile" />
<Content Include="@(Protobuf)" />
<None Remove="@(Protobuf)" />
<Protobuf Include="Proto\basket.proto" GrpcServices="Server" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" />
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBus\EventBus.csproj" />
<ProjectReference Include="..\..\Services.Common\Services.Common.csproj" />
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="Basket.FunctionalTests" />
</ItemGroup>
</Project>

View File

@ -1,7 +0,0 @@
namespace Microsoft.eShopOnContainers.Services.Basket.API;
public class BasketSettings
{
public string ConnectionString { get; set; }
}

View File

@ -23,7 +23,6 @@ public class BasketController : ControllerBase
}
[HttpGet("{id}")]
[ProducesResponseType(typeof(CustomerBasket), (int)HttpStatusCode.OK)]
public async Task<ActionResult<CustomerBasket>> GetBasketByIdAsync(string id)
{
var basket = await _repository.GetBasketAsync(id);
@ -32,7 +31,6 @@ public class BasketController : ControllerBase
}
[HttpPost]
[ProducesResponseType(typeof(CustomerBasket), (int)HttpStatusCode.OK)]
public async Task<ActionResult<CustomerBasket>> UpdateBasketAsync([FromBody] CustomerBasket value)
{
return Ok(await _repository.UpdateBasketAsync(value));
@ -40,8 +38,8 @@ public class BasketController : ControllerBase
[Route("checkout")]
[HttpPost]
[ProducesResponseType((int)HttpStatusCode.Accepted)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType(StatusCodes.Status202Accepted)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult> CheckoutAsync([FromBody] BasketCheckout basketCheckout, [FromHeader(Name = "x-requestid")] string requestId)
{
var userId = _identityService.GetUserIdentity();
@ -56,7 +54,7 @@ public class BasketController : ControllerBase
return BadRequest();
}
var userName = this.HttpContext.User.FindFirst(x => x.Type == ClaimTypes.Name).Value;
var userName = User.FindFirst(x => x.Type == ClaimTypes.Name).Value;
var eventMessage = new UserCheckoutAcceptedIntegrationEvent(userId, userName, basketCheckout.City, basketCheckout.Street,
basketCheckout.State, basketCheckout.Country, basketCheckout.ZipCode, basketCheckout.CardNumber, basketCheckout.CardHolderName,
@ -71,7 +69,7 @@ public class BasketController : ControllerBase
}
catch (Exception ex)
{
_logger.LogError(ex, "ERROR Publishing integration event: {IntegrationEventId} from {AppName}", eventMessage.Id, Program.AppName);
_logger.LogError(ex, "Error Publishing integration event: {IntegrationEventId}", eventMessage.Id);
throw;
}
@ -81,7 +79,7 @@ public class BasketController : ControllerBase
// DELETE api/values/5
[HttpDelete("{id}")]
[ProducesResponseType(typeof(void), (int)HttpStatusCode.OK)]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task DeleteBasketByIdAsync(string id)
{
await _repository.DeleteBasketAsync(id);

View File

@ -1,11 +0,0 @@
namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers;
public class HomeController : Controller
{
// GET: /<controller>/
public IActionResult Index()
{
return new RedirectResult("~/swagger");
}
}

View File

@ -1,37 +0,0 @@
namespace Microsoft.eShopOnContainers.Services.Basket.API;
public static class CustomExtensionMethods
{
public static IServiceCollection AddCustomHealthCheck(this IServiceCollection services, IConfiguration configuration)
{
var hcBuilder = services.AddHealthChecks();
hcBuilder.AddCheck("self", () => HealthCheckResult.Healthy());
hcBuilder
.AddRedis(
configuration["ConnectionString"],
name: "redis-check",
tags: new string[] { "redis" });
if (configuration.GetValue<bool>("AzureServiceBusEnabled"))
{
hcBuilder
.AddAzureServiceBusTopic(
configuration["EventBusConnection"],
topicName: "eshop_event_bus",
name: "basket-servicebus-check",
tags: new string[] { "servicebus" });
}
else
{
hcBuilder
.AddRabbitMQ(
$"amqp://{configuration["EventBusConnection"]}",
name: "basket-rabbitmqbus-check",
tags: new string[] { "rabbitmqbus" });
}
return services;
}
}

View File

@ -1,8 +1,8 @@
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
# It's important to keep lines from here down to "COPY . ." identical in all Dockerfiles
@ -11,7 +11,6 @@ COPY "eShopOnContainers-ServicesAndWebApps.sln" "eShopOnContainers-ServicesAndWe
COPY "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj" "ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj"
COPY "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj" "ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj"
COPY "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj" "BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj"
COPY "BuildingBlocks/EventBus/EventBus/EventBus.csproj" "BuildingBlocks/EventBus/EventBus/EventBus.csproj"
COPY "BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj" "BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj"
COPY "BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj" "BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj"
@ -33,6 +32,8 @@ COPY "Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj"
COPY "Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj" "Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj"
COPY "Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj" "Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj"
COPY "Services/Payment/Payment.API/Payment.API.csproj" "Services/Payment/Payment.API/Payment.API.csproj"
COPY "Services/Contact/Contact.API/Contact.API.csproj" "Services/Contact/Contact.API/Contact.API.csproj"
COPY "Services/Services.Common/Services.Common.csproj" "Services/Services.Common/Services.Common.csproj"
COPY "Services/Webhooks/Webhooks.API/Webhooks.API.csproj" "Services/Webhooks/Webhooks.API/Webhooks.API.csproj"
COPY "Tests/Services/Application.FunctionalTests/Application.FunctionalTests.csproj" "Tests/Services/Application.FunctionalTests/Application.FunctionalTests.csproj"
COPY "Web/WebhookClient/WebhookClient.csproj" "Web/WebhookClient/WebhookClient.csproj"
@ -42,6 +43,7 @@ COPY "Web/WebStatus/WebStatus.csproj" "Web/WebStatus/WebStatus.csproj"
COPY "docker-compose.dcproj" "docker-compose.dcproj"
COPY "Directory.Packages.props" "Directory.Packages.props"
COPY "NuGet.config" "NuGet.config"
RUN dotnet restore "eShopOnContainers-ServicesAndWebApps.sln"

View File

@ -1,4 +1,4 @@
FROM mcr.microsoft.com/dotnet/sdk:6.0
FROM mcr.microsoft.com/dotnet/sdk:7.0
ARG BUILD_CONFIGURATION=Debug
ENV ASPNETCORE_ENVIRONMENT=Development
ENV DOTNET_USE_POLLING_FILE_WATCHER=true

View File

@ -0,0 +1,20 @@
public static class Extensions
{
public static IServiceCollection AddHealthChecks(this IServiceCollection services, IConfiguration configuration)
{
services.AddHealthChecks()
.AddRedis(_ => configuration.GetRequiredConnectionString("redis"), "redis", tags: new[] { "ready", "liveness" });
return services;
}
public static IServiceCollection AddRedis(this IServiceCollection services, IConfiguration configuration)
{
return services.AddSingleton(sp =>
{
var redisConfig = ConfigurationOptions.Parse(configuration.GetRequiredConnectionString("redis"), true);
return ConnectionMultiplexer.Connect(redisConfig);
});
}
}

Some files were not shown because too many files have changed in this diff Show More