├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .gitignore ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── LICENSE ├── PizzaConf ├── .dockerignore ├── PizzaConf.Checkout.Api │ ├── Data │ │ ├── DbInitializer.cs │ │ └── ShoppingCartContext.cs │ ├── Dockerfile │ ├── PizzaConf.Checkout.Api.csproj │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Services │ │ └── CartService.cs │ ├── appsettings.Development.json │ └── appsettings.json ├── PizzaConf.DeliveryTracker │ ├── .gitignore │ ├── OrderTrackingFunction.cs │ ├── PizzaConf.DeliveryTracker.csproj │ ├── Properties │ │ ├── ServiceDependencies │ │ │ ├── local │ │ │ │ └── signalr1.arm.json │ │ │ └── pizzaconftracker - Zip Deploy │ │ │ │ ├── appInsights1.arm.json │ │ │ │ ├── profile.arm.json │ │ │ │ ├── signalr1.arm.json │ │ │ │ └── storage1.arm.json │ │ ├── serviceDependencies.json │ │ ├── serviceDependencies.local.json │ │ └── serviceDependencies.pizzaconftracker - Zip Deploy.json │ ├── Startup.cs │ └── host.json ├── PizzaConf.Menu.Api │ ├── Data │ │ ├── DbInitializer.cs │ │ ├── PizzaContext.cs │ │ └── StorageInitializer.cs │ ├── Dockerfile │ ├── PizzaConf.Menu.Api.csproj │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Services │ │ └── PizzaService.cs │ ├── appsettings.Development.json │ ├── appsettings.json │ └── media │ │ ├── order1.jpg │ │ ├── order2.jpg │ │ ├── order3.jpg │ │ ├── order4.jpg │ │ ├── pizza.jpg │ │ ├── pizza1.jpg │ │ ├── pizza2.jpg │ │ ├── pizza3.jpg │ │ └── pizza4.jpg ├── PizzaConf.Models │ ├── OrderedPizza.cs │ ├── Pizza.cs │ ├── PizzaConf.Models.csproj │ └── TrackingMessage.cs ├── PizzaConf.Web │ ├── App.razor │ ├── Configuration │ │ └── DaprAppId.cs │ ├── Data │ │ ├── CartWebService.cs │ │ └── PizzaWebService.cs │ ├── Dockerfile │ ├── Pages │ │ ├── Cart.razor │ │ ├── Error.cshtml │ │ ├── Error.cshtml.cs │ │ ├── PizzaDetails.razor │ │ ├── PizzaMenu.razor │ │ ├── Tracking.razor │ │ └── _Host.cshtml │ ├── PizzaConf.Web.csproj │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Shared │ │ ├── MainLayout.razor │ │ ├── MainLayout.razor.css │ │ ├── NavMenu.razor │ │ └── NavMenu.razor.css │ ├── _Imports.razor │ ├── appsettings.Development.json │ ├── appsettings.json │ └── wwwroot │ │ ├── css │ │ ├── bootstrap │ │ │ ├── bootstrap.min.css │ │ │ └── bootstrap.min.css.map │ │ ├── open-iconic │ │ │ ├── FONT-LICENSE │ │ │ ├── ICON-LICENSE │ │ │ ├── README.md │ │ │ └── font │ │ │ │ ├── css │ │ │ │ └── open-iconic-bootstrap.min.css │ │ │ │ └── fonts │ │ │ │ ├── open-iconic.eot │ │ │ │ ├── open-iconic.otf │ │ │ │ ├── open-iconic.svg │ │ │ │ ├── open-iconic.ttf │ │ │ │ └── open-iconic.woff │ │ └── site.css │ │ └── favicon.png └── PizzaConf.sln ├── README.md ├── azure.yaml └── infra ├── abbreviations.json ├── app ├── checkout.bicep ├── checkout.parameters.json ├── menu.bicep ├── menu.parameters.json ├── web.bicep └── web.parameters.json ├── core ├── app-config │ └── azure-app-config.bicep ├── cdn │ └── endpoint.bicep ├── container-apps │ └── container-apps.bicep ├── host │ └── functions.bicep ├── key-vault │ └── key-vault.bicep ├── log-analytics │ └── log-analytics.bicep ├── monitor │ ├── applicationinsights-dashboard.bicep │ ├── applicationinsights.bicep │ ├── loganalytics.bicep │ └── monitoring.bicep ├── signal-r │ └── azure-signal-r.bicep ├── sql-server │ └── sql-azure.bicep └── storage │ └── storage-account.bicep ├── main.bicep └── main.parameters.json /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG VARIANT=bullseye 2 | FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT} 3 | RUN curl -fsSL https://aka.ms/install-azd.sh | bash \ 4 | && apt-get update && rm -rf /var/lib/apt/lists/* -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Azure Developer CLI", 3 | "build": { 4 | "dockerfile": "Dockerfile", 5 | "args": { 6 | "VARIANT": "bullseye" 7 | } 8 | }, 9 | "features": { 10 | "ghcr.io/devcontainers/features/azure-cli:1": { 11 | "version": "2.38" 12 | }, 13 | "ghcr.io/devcontainers/features/docker-from-docker:1": { 14 | "version": "20.10" 15 | }, 16 | "ghcr.io/devcontainers/features/dotnet:1": { 17 | "version": "6.0" 18 | }, 19 | "ghcr.io/devcontainers/features/github-cli:1": { 20 | "version": "2" 21 | } 22 | }, 23 | "extensions": [ 24 | "ms-azuretools.azure-dev", 25 | "ms-azuretools.vscode-bicep", 26 | "ms-azuretools.vscode-docker", 27 | "ms-dotnettools.csharp", 28 | "ms-dotnettools.vscode-dotnet-runtime", 29 | "ms-azuretools.vscode-azurefunctions" 30 | ], 31 | "postCreateCommand": "", 32 | "remoteUser": "vscode" 33 | } 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | /PizzaConf/PizzaConf.Menu.Api/pizza.db-wal 352 | /PizzaConf/PizzaConf.Menu.Api/pizza.db-shm 353 | /PizzaConf/PizzaConf.Menu.Api/pizza.db 354 | /PizzaConf/PizzaConf.Checkout.Api/checkout.db 355 | /PizzaConf/PizzaConf.Checkout.Api/checkout.db-shm 356 | /PizzaConf/PizzaConf.Checkout.Api/checkout.db-wal 357 | 358 | .azure 359 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-azuretools.vscode-azurefunctions", 4 | "ms-dotnettools.csharp" 5 | ] 6 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Attach to .NET Functions", 6 | "type": "coreclr", 7 | "request": "attach", 8 | "processId": "${command:azureFunctions.pickProcess}" 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "azureFunctions.deploySubpath": "PizzaConf/PizzaConf.DeliveryTracker/bin/Release/net6.0/publish", 3 | "azureFunctions.projectLanguage": "C#", 4 | "azureFunctions.projectRuntime": "~4", 5 | "debug.internalConsoleOptions": "neverOpen", 6 | "azureFunctions.projectSubpath": "PizzaConf/PizzaConf.DeliveryTracker", 7 | "azureFunctions.preDeployTask": "publish (functions)" 8 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "clean (functions)", 6 | "command": "dotnet", 7 | "args": [ 8 | "clean", 9 | "/property:GenerateFullPaths=true", 10 | "/consoleloggerparameters:NoSummary" 11 | ], 12 | "type": "process", 13 | "problemMatcher": "$msCompile", 14 | "options": { 15 | "cwd": "${workspaceFolder}/PizzaConf/PizzaConf.DeliveryTracker" 16 | } 17 | }, 18 | { 19 | "label": "build (functions)", 20 | "command": "dotnet", 21 | "args": [ 22 | "build", 23 | "/property:GenerateFullPaths=true", 24 | "/consoleloggerparameters:NoSummary" 25 | ], 26 | "type": "process", 27 | "dependsOn": "clean (functions)", 28 | "group": { 29 | "kind": "build", 30 | "isDefault": true 31 | }, 32 | "problemMatcher": "$msCompile", 33 | "options": { 34 | "cwd": "${workspaceFolder}/PizzaConf/PizzaConf.DeliveryTracker" 35 | } 36 | }, 37 | { 38 | "label": "clean release (functions)", 39 | "command": "dotnet", 40 | "args": [ 41 | "clean", 42 | "--configuration", 43 | "Release", 44 | "/property:GenerateFullPaths=true", 45 | "/consoleloggerparameters:NoSummary" 46 | ], 47 | "type": "process", 48 | "problemMatcher": "$msCompile", 49 | "options": { 50 | "cwd": "${workspaceFolder}/PizzaConf/PizzaConf.DeliveryTracker" 51 | } 52 | }, 53 | { 54 | "label": "publish (functions)", 55 | "command": "dotnet", 56 | "args": [ 57 | "publish", 58 | "--configuration", 59 | "Release", 60 | "/property:GenerateFullPaths=true", 61 | "/consoleloggerparameters:NoSummary" 62 | ], 63 | "type": "process", 64 | "dependsOn": "clean release (functions)", 65 | "problemMatcher": "$msCompile", 66 | "options": { 67 | "cwd": "${workspaceFolder}/PizzaConf/PizzaConf.DeliveryTracker" 68 | } 69 | }, 70 | { 71 | "type": "func", 72 | "dependsOn": "build (functions)", 73 | "options": { 74 | "cwd": "${workspaceFolder}/PizzaConf/PizzaConf.DeliveryTracker/bin/Debug/net6.0" 75 | }, 76 | "command": "host start", 77 | "isBackground": true, 78 | "problemMatcher": "$func-dotnet-watch" 79 | } 80 | ] 81 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Matt Soucoup 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PizzaConf/.dockerignore: -------------------------------------------------------------------------------- 1 | **/.classpath 2 | **/.dockerignore 3 | **/.env 4 | **/.git 5 | **/.gitignore 6 | **/.project 7 | **/.settings 8 | **/.toolstarget 9 | **/.vs 10 | **/.vscode 11 | **/*.*proj.user 12 | **/*.dbmdl 13 | **/*.jfm 14 | **/azds.yaml 15 | **/bin 16 | **/charts 17 | **/docker-compose* 18 | **/Dockerfile* 19 | **/node_modules 20 | **/npm-debug.log 21 | **/obj 22 | **/secrets.dev.yaml 23 | **/values.dev.yaml 24 | LICENSE 25 | README.md -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Checkout.Api/Data/DbInitializer.cs: -------------------------------------------------------------------------------- 1 | namespace PizzaConf.Checkout.Api.Data; 2 | 3 | public static class DbInitializer 4 | { 5 | public static void Initialize(ShoppingCartContext context) 6 | { 7 | // Start w/o anything in the shopping cart 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Checkout.Api/Data/ShoppingCartContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using PizzaConf.Models; 3 | 4 | namespace PizzaConf.Checkout.Api.Data; 5 | 6 | public class ShoppingCartContext : DbContext 7 | { 8 | public ShoppingCartContext(DbContextOptions options): base(options) { } 9 | 10 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.LogTo(Console.WriteLine); 11 | 12 | public DbSet Pizzas => Set(); 13 | } 14 | 15 | public static class Extensions 16 | { 17 | public static void CreateDbIfNotExists(this IHost host) 18 | { 19 | using var scope = host.Services.CreateScope(); 20 | 21 | var services = scope.ServiceProvider; 22 | var context = services.GetRequiredService(); 23 | context.Database.EnsureCreated(); 24 | DbInitializer.Initialize(context); 25 | } 26 | } -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Checkout.Api/Dockerfile: -------------------------------------------------------------------------------- 1 | #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. 2 | 3 | FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base 4 | WORKDIR /app 5 | EXPOSE 80 6 | EXPOSE 443 7 | 8 | FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build 9 | WORKDIR /src 10 | COPY ["PizzaConf.Checkout.Api/PizzaConf.Checkout.Api.csproj", "PizzaConf.Checkout.Api/"] 11 | COPY ["PizzaConf.Models/PizzaConf.Models.csproj", "PizzaConf.Models/"] 12 | RUN dotnet restore "PizzaConf.Checkout.Api/PizzaConf.Checkout.Api.csproj" 13 | COPY . . 14 | WORKDIR "/src/PizzaConf.Checkout.Api" 15 | RUN dotnet build "PizzaConf.Checkout.Api.csproj" -c Release -o /app/build 16 | 17 | FROM build AS publish 18 | RUN dotnet publish "PizzaConf.Checkout.Api.csproj" -c Release -o /app/publish /p:UseAppHost=false 19 | 20 | FROM base AS final 21 | WORKDIR /app 22 | COPY --from=publish /app/publish . 23 | ENTRYPOINT ["dotnet", "PizzaConf.Checkout.Api.dll"] -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Checkout.Api/PizzaConf.Checkout.Api.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0 5 | enable 6 | enable 7 | d54c56a0-a5e4-48c8-96da-c9376c0f5930 8 | Linux 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | all 17 | runtime; build; native; contentfiles; analyzers; buildtransitive 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Checkout.Api/Program.cs: -------------------------------------------------------------------------------- 1 | using PizzaConf.Checkout.Api.Data; 2 | using PizzaConf.Checkout.Api.Services; 3 | using Microsoft.AspNetCore.Mvc; 4 | using PizzaConf.Models; 5 | using Azure.Identity; 6 | 7 | var builder = WebApplication.CreateBuilder(args); 8 | 9 | // Add services to the container. 10 | // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle 11 | builder.Services.AddEndpointsApiExplorer(); 12 | builder.Services.AddSwaggerGen(); 13 | 14 | builder.Configuration.AddAzureAppConfiguration((options) => 15 | { 16 | string? appConfigUrl = builder.Configuration["appConfigUrl"] ?? ""; 17 | 18 | if (string.IsNullOrEmpty(appConfigUrl)) 19 | throw new NullReferenceException($"{nameof(appConfigUrl)} setting needs to have the Azure App Config url set."); 20 | 21 | options.Connect(new Uri(appConfigUrl), new DefaultAzureCredential()) 22 | .Select("CheckoutDb") 23 | .ConfigureKeyVault((kvOptions) => kvOptions.SetCredential(new DefaultAzureCredential())); 24 | }); 25 | 26 | //builder.Services.AddSqlite("Data Source=checkout.db"); 27 | builder.Services.AddSqlServer 28 | (builder.Configuration["CheckoutDb"] ?? "Server=(localdb)\\mssqllocaldb;Database=CartContext-0e9;Trusted_Connection=True;MultipleActiveResultSets=true", 29 | (options) => options.EnableRetryOnFailure()); 30 | 31 | 32 | builder.Services.AddTransient(); 33 | 34 | var app = builder.Build(); 35 | 36 | // Configure the HTTP request pipeline. 37 | if (app.Environment.IsDevelopment()) 38 | { 39 | app.UseSwagger(); 40 | app.UseSwaggerUI(); 41 | } 42 | 43 | app.UseHttpsRedirection(); 44 | 45 | app.MapGet("/cart", async ([FromServices]CartService cart) => 46 | { 47 | var contents = await cart.GetCartContents(); 48 | 49 | return Results.Ok(contents); 50 | }) 51 | .WithName("GetCartContents") 52 | .Produces>(StatusCodes.Status200OK) 53 | .WithOpenApi(); 54 | 55 | app.MapDelete("/cart", async ([FromServices] CartService cart) => 56 | { 57 | await cart.PlaceOrder(); 58 | 59 | return Results.NoContent(); 60 | }) 61 | .WithName("PlaceOrder") 62 | .Produces(StatusCodes.Status204NoContent) 63 | .WithOpenApi(); 64 | 65 | app.MapPost("/order", async ([FromBody] OrderedPizza pizza, [FromServices] CartService cart) => 66 | { 67 | var orderedPizza = await cart.OrderPizza(pizza); 68 | 69 | return Results.CreatedAtRoute(routeName: "OrderPizza", value: orderedPizza); 70 | }) 71 | .WithName("OrderPizza") 72 | .Produces(StatusCodes.Status201Created) 73 | .WithOpenApi(); 74 | 75 | app.CreateDbIfNotExists(); 76 | 77 | app.Run(); 78 | 79 | 80 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Checkout.Api/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "http": { 4 | "commandName": "Project", 5 | "launchBrowser": true, 6 | "launchUrl": "swagger", 7 | "environmentVariables": { 8 | "ASPNETCORE_ENVIRONMENT": "Development" 9 | }, 10 | "dotnetRunMessages": true, 11 | "applicationUrl": "http://localhost:5222" 12 | }, 13 | "https": { 14 | "commandName": "Project", 15 | "launchBrowser": true, 16 | "launchUrl": "swagger", 17 | "environmentVariables": { 18 | "ASPNETCORE_ENVIRONMENT": "Development" 19 | }, 20 | "dotnetRunMessages": true, 21 | "applicationUrl": "https://localhost:7226;http://localhost:5222" 22 | }, 23 | "IIS Express": { 24 | "commandName": "IISExpress", 25 | "launchBrowser": true, 26 | "launchUrl": "swagger", 27 | "environmentVariables": { 28 | "ASPNETCORE_ENVIRONMENT": "Development" 29 | } 30 | }, 31 | "Docker": { 32 | "commandName": "Docker", 33 | "launchBrowser": true, 34 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", 35 | "publishAllPorts": true, 36 | "useSSL": true 37 | } 38 | }, 39 | "$schema": "https://json.schemastore.org/launchsettings.json", 40 | "iisSettings": { 41 | "windowsAuthentication": false, 42 | "anonymousAuthentication": true, 43 | "iisExpress": { 44 | "applicationUrl": "http://localhost:62560", 45 | "sslPort": 44321 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Checkout.Api/Services/CartService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using PizzaConf.Checkout.Api.Data; 3 | using PizzaConf.Models; 4 | 5 | namespace PizzaConf.Checkout.Api.Services; 6 | 7 | public class CartService 8 | { 9 | private readonly ShoppingCartContext _context; 10 | 11 | public CartService(ShoppingCartContext shoppingCartContext) 12 | { 13 | _context = shoppingCartContext; 14 | } 15 | 16 | public async Task> GetCartContents() 17 | { 18 | var orderedPizzas = await _context.Pizzas.AsNoTracking().ToListAsync(); 19 | 20 | return orderedPizzas; 21 | } 22 | 23 | public async Task OrderPizza(OrderedPizza pizza) 24 | { 25 | await _context.Pizzas.AddAsync(pizza); 26 | 27 | await _context.SaveChangesAsync(); 28 | 29 | return pizza; 30 | } 31 | 32 | public async Task PlaceOrder() 33 | { 34 | // just delete everything 35 | _context.Pizzas.RemoveRange(await _context.Pizzas.ToArrayAsync()); 36 | 37 | await _context.SaveChangesAsync(); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Checkout.Api/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "appConfigUrl": "https://pizzaconfconfig.azconfig.io" 9 | } 10 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Checkout.Api/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.DeliveryTracker/.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # Azure Functions localsettings file 5 | local.settings.json 6 | 7 | # User-specific files 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | bld/ 24 | [Bb]in/ 25 | [Oo]bj/ 26 | [Ll]og/ 27 | 28 | # Visual Studio 2015 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # MSTest test Results 34 | [Tt]est[Rr]esult*/ 35 | [Bb]uild[Ll]og.* 36 | 37 | # NUNIT 38 | *.VisualState.xml 39 | TestResult.xml 40 | 41 | # Build Results of an ATL Project 42 | [Dd]ebugPS/ 43 | [Rr]eleasePS/ 44 | dlldata.c 45 | 46 | # DNX 47 | project.lock.json 48 | project.fragment.lock.json 49 | artifacts/ 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | *.VC.db 88 | *.VC.VC.opendb 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | *.sap 95 | 96 | # TFS 2012 Local Workspace 97 | $tf/ 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | *.DotSettings.user 106 | 107 | # JustCode is a .NET coding add-in 108 | .JustCode 109 | 110 | # TeamCity is a build add-in 111 | _TeamCity* 112 | 113 | # DotCover is a Code Coverage Tool 114 | *.dotCover 115 | 116 | # NCrunch 117 | _NCrunch_* 118 | .*crunch*.local.xml 119 | nCrunchTemp_* 120 | 121 | # MightyMoose 122 | *.mm.* 123 | AutoTest.Net/ 124 | 125 | # Web workbench (sass) 126 | .sass-cache/ 127 | 128 | # Installshield output folder 129 | [Ee]xpress/ 130 | 131 | # DocProject is a documentation generator add-in 132 | DocProject/buildhelp/ 133 | DocProject/Help/*.HxT 134 | DocProject/Help/*.HxC 135 | DocProject/Help/*.hhc 136 | DocProject/Help/*.hhk 137 | DocProject/Help/*.hhp 138 | DocProject/Help/Html2 139 | DocProject/Help/html 140 | 141 | # Click-Once directory 142 | publish/ 143 | 144 | # Publish Web Output 145 | *.[Pp]ublish.xml 146 | *.azurePubxml 147 | # TODO: Comment the next line if you want to checkin your web deploy settings 148 | # but database connection strings (with potential passwords) will be unencrypted 149 | #*.pubxml 150 | *.publishproj 151 | 152 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 153 | # checkin your Azure Web App publish settings, but sensitive information contained 154 | # in these scripts will be unencrypted 155 | PublishScripts/ 156 | 157 | # NuGet Packages 158 | *.nupkg 159 | # The packages folder can be ignored because of Package Restore 160 | **/packages/* 161 | # except build/, which is used as an MSBuild target. 162 | !**/packages/build/ 163 | # Uncomment if necessary however generally it will be regenerated when needed 164 | #!**/packages/repositories.config 165 | # NuGet v3's project.json files produces more ignoreable files 166 | *.nuget.props 167 | *.nuget.targets 168 | 169 | # Microsoft Azure Build Output 170 | csx/ 171 | *.build.csdef 172 | 173 | # Microsoft Azure Emulator 174 | ecf/ 175 | rcf/ 176 | 177 | # Windows Store app package directories and files 178 | AppPackages/ 179 | BundleArtifacts/ 180 | Package.StoreAssociation.xml 181 | _pkginfo.txt 182 | 183 | # Visual Studio cache files 184 | # files ending in .cache can be ignored 185 | *.[Cc]ache 186 | # but keep track of directories ending in .cache 187 | !*.[Cc]ache/ 188 | 189 | # Others 190 | ClientBin/ 191 | ~$* 192 | *~ 193 | *.dbmdl 194 | *.dbproj.schemaview 195 | *.jfm 196 | *.pfx 197 | *.publishsettings 198 | node_modules/ 199 | orleans.codegen.cs 200 | 201 | # Since there are multiple workflows, uncomment next line to ignore bower_components 202 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 203 | #bower_components/ 204 | 205 | # RIA/Silverlight projects 206 | Generated_Code/ 207 | 208 | # Backup & report files from converting an old project file 209 | # to a newer Visual Studio version. Backup files are not needed, 210 | # because we have git ;-) 211 | _UpgradeReport_Files/ 212 | Backup*/ 213 | UpgradeLog*.XML 214 | UpgradeLog*.htm 215 | 216 | # SQL Server files 217 | *.mdf 218 | *.ldf 219 | 220 | # Business Intelligence projects 221 | *.rdl.data 222 | *.bim.layout 223 | *.bim_*.settings 224 | 225 | # Microsoft Fakes 226 | FakesAssemblies/ 227 | 228 | # GhostDoc plugin setting file 229 | *.GhostDoc.xml 230 | 231 | # Node.js Tools for Visual Studio 232 | .ntvs_analysis.dat 233 | 234 | # Visual Studio 6 build log 235 | *.plg 236 | 237 | # Visual Studio 6 workspace options file 238 | *.opt 239 | 240 | # Visual Studio LightSwitch build output 241 | **/*.HTMLClient/GeneratedArtifacts 242 | **/*.DesktopClient/GeneratedArtifacts 243 | **/*.DesktopClient/ModelManifest.xml 244 | **/*.Server/GeneratedArtifacts 245 | **/*.Server/ModelManifest.xml 246 | _Pvt_Extensions 247 | 248 | # Paket dependency manager 249 | .paket/paket.exe 250 | paket-files/ 251 | 252 | # FAKE - F# Make 253 | .fake/ 254 | 255 | # JetBrains Rider 256 | .idea/ 257 | *.sln.iml 258 | 259 | # CodeRush 260 | .cr/ 261 | 262 | # Python Tools for Visual Studio (PTVS) 263 | __pycache__/ 264 | *.pyc -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.DeliveryTracker/OrderTrackingFunction.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using Microsoft.Azure.WebJobs; 3 | using Microsoft.Azure.WebJobs.Extensions.Http; 4 | using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes; 5 | using Microsoft.Azure.WebJobs.Extensions.SignalRService; 6 | using Microsoft.Extensions.Configuration; 7 | 8 | using Microsoft.OpenApi.Models; 9 | using System.Threading.Tasks; 10 | 11 | using PizzaConf.Models; 12 | using System.Net; 13 | using Microsoft.AspNetCore.Mvc; 14 | 15 | namespace PizzaConf.DeliveryTracker 16 | { 17 | public class OrderTrackingFunction 18 | { 19 | IConfiguration _configuration; 20 | string _signalRConnectionString; 21 | 22 | public OrderTrackingFunction(IConfiguration configuration) 23 | { 24 | _configuration = configuration; 25 | _signalRConnectionString = _configuration["AzureSignalRConnectionString"]; 26 | } 27 | 28 | [FunctionName("negotiate")] 29 | [OpenApiOperation(operationId:"negotiate", tags: new[] {"register with signalr"},Summary = "Register with SignalR")] 30 | [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(SignalRConnectionInfo), Description = "The OK response")] 31 | public SignalRConnectionInfo Negotiate( 32 | [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req, 33 | [SignalRConnectionInfo(HubName = "DeliveryInfo")] SignalRConnectionInfo connectionInfo) 34 | { 35 | return connectionInfo; 36 | } 37 | 38 | [FunctionName("trackorder")] 39 | [OpenApiOperation(operationId: "TrackOrder", tags: new[] { "track order" })] 40 | [OpenApiParameter(name: "orderId", In = ParameterLocation.Path, Required = true, Type = typeof(int), Description = "The order id to track")] 41 | [OpenApiParameter(name: "status", In = ParameterLocation.Path, Required = true, Type = typeof(int), Description = "New delivery status of the order")] 42 | [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(TrackingMessage), Description = "The OK response")] 43 | public async Task TrackOrder( 44 | [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "{orderId:int}/{status:int}")] HttpRequest req, int orderId, int status, 45 | [SignalR(HubName = "DeliveryInfo")] IAsyncCollector deliveryMessages) 46 | { 47 | string url; 48 | string statusText; 49 | 50 | switch (status) 51 | { 52 | case 1: 53 | url = "order1.jpg"; 54 | statusText = "Order received"; 55 | break; 56 | case 2: 57 | url = "order2.jpg"; 58 | statusText = "Order being prepped"; 59 | break; 60 | case 3: 61 | url = "order3.jpg"; 62 | statusText = "It's in the oven!"; 63 | break; 64 | default: 65 | url = "order4.jpg"; 66 | statusText = "It's on it's way!"; 67 | break; 68 | } 69 | 70 | TrackingMessage msg = new() { StatusUrl = url, Status = statusText, OrderId = orderId }; 71 | 72 | await deliveryMessages.AddAsync(new SignalRMessage 73 | { 74 | Target = "newMessage", 75 | Arguments = new[] { msg } 76 | }); 77 | 78 | return new OkObjectResult(msg); 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.DeliveryTracker/PizzaConf.DeliveryTracker.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net6.0 4 | v4 5 | 02fdf457-a403-4fbe-9d5c-b1937b1c94cc 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | PreserveNewest 22 | 23 | 24 | PreserveNewest 25 | Never 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.DeliveryTracker/Properties/ServiceDependencies/local/signalr1.arm.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "resourceGroupName": { 6 | "type": "string", 7 | "defaultValue": "dotnetconf", 8 | "metadata": { 9 | "_parameterType": "resourceGroup", 10 | "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." 11 | } 12 | }, 13 | "resourceGroupLocation": { 14 | "type": "string", 15 | "defaultValue": "eastus", 16 | "metadata": { 17 | "_parameterType": "location", 18 | "description": "Location of the resource group. Resource groups could have different location than resources." 19 | } 20 | }, 21 | "resourceLocation": { 22 | "type": "string", 23 | "defaultValue": "[parameters('resourceGroupLocation')]", 24 | "metadata": { 25 | "_parameterType": "location", 26 | "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." 27 | } 28 | } 29 | }, 30 | "resources": [ 31 | { 32 | "type": "Microsoft.Resources/resourceGroups", 33 | "name": "[parameters('resourceGroupName')]", 34 | "location": "[parameters('resourceGroupLocation')]", 35 | "apiVersion": "2019-10-01" 36 | }, 37 | { 38 | "type": "Microsoft.Resources/deployments", 39 | "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat('pizzaconfdelivery', subscription().subscriptionId)))]", 40 | "resourceGroup": "[parameters('resourceGroupName')]", 41 | "apiVersion": "2019-10-01", 42 | "dependsOn": [ 43 | "[parameters('resourceGroupName')]" 44 | ], 45 | "properties": { 46 | "mode": "Incremental", 47 | "template": { 48 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 49 | "contentVersion": "1.0.0.0", 50 | "resources": [ 51 | { 52 | "sku": { 53 | "name": "Standard_S1", 54 | "tier": "Standard", 55 | "size": "S1", 56 | "capacity": 1 57 | }, 58 | "location": "[parameters('resourceLocation')]", 59 | "name": "pizzaconfdelivery", 60 | "type": "Microsoft.SignalRService/SignalR", 61 | "apiVersion": "2018-10-01" 62 | } 63 | ] 64 | } 65 | } 66 | } 67 | ], 68 | "metadata": { 69 | "_dependencyType": "signalr.function" 70 | } 71 | } -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.DeliveryTracker/Properties/ServiceDependencies/pizzaconftracker - Zip Deploy/appInsights1.arm.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "resourceGroupName": { 6 | "type": "string", 7 | "defaultValue": "dotnetconf", 8 | "metadata": { 9 | "_parameterType": "resourceGroup", 10 | "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." 11 | } 12 | }, 13 | "resourceGroupLocation": { 14 | "type": "string", 15 | "defaultValue": "eastus", 16 | "metadata": { 17 | "_parameterType": "location", 18 | "description": "Location of the resource group. Resource groups could have different location than resources." 19 | } 20 | }, 21 | "resourceLocation": { 22 | "type": "string", 23 | "defaultValue": "[parameters('resourceGroupLocation')]", 24 | "metadata": { 25 | "_parameterType": "location", 26 | "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." 27 | } 28 | } 29 | }, 30 | "resources": [ 31 | { 32 | "type": "Microsoft.Resources/resourceGroups", 33 | "name": "[parameters('resourceGroupName')]", 34 | "location": "[parameters('resourceGroupLocation')]", 35 | "apiVersion": "2019-10-01" 36 | }, 37 | { 38 | "type": "Microsoft.Resources/deployments", 39 | "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat('pizzaconf-insights', subscription().subscriptionId)))]", 40 | "resourceGroup": "[parameters('resourceGroupName')]", 41 | "apiVersion": "2019-10-01", 42 | "dependsOn": [ 43 | "[parameters('resourceGroupName')]" 44 | ], 45 | "properties": { 46 | "mode": "Incremental", 47 | "template": { 48 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 49 | "contentVersion": "1.0.0.0", 50 | "resources": [ 51 | { 52 | "name": "pizzaconf-insights", 53 | "type": "microsoft.insights/components", 54 | "location": "[parameters('resourceLocation')]", 55 | "kind": "web", 56 | "properties": {}, 57 | "apiVersion": "2015-05-01" 58 | } 59 | ] 60 | } 61 | } 62 | } 63 | ], 64 | "metadata": { 65 | "_dependencyType": "appInsights.azure" 66 | } 67 | } -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.DeliveryTracker/Properties/ServiceDependencies/pizzaconftracker - Zip Deploy/profile.arm.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "metadata": { 5 | "_dependencyType": "compute.function.windows.appService" 6 | }, 7 | "parameters": { 8 | "resourceGroupName": { 9 | "type": "string", 10 | "defaultValue": "dotnetconf", 11 | "metadata": { 12 | "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." 13 | } 14 | }, 15 | "resourceGroupLocation": { 16 | "type": "string", 17 | "defaultValue": "eastus", 18 | "metadata": { 19 | "description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support." 20 | } 21 | }, 22 | "resourceName": { 23 | "type": "string", 24 | "defaultValue": "pizzaconftracker", 25 | "metadata": { 26 | "description": "Name of the main resource to be created by this template." 27 | } 28 | }, 29 | "resourceLocation": { 30 | "type": "string", 31 | "defaultValue": "[parameters('resourceGroupLocation')]", 32 | "metadata": { 33 | "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." 34 | } 35 | } 36 | }, 37 | "resources": [ 38 | { 39 | "type": "Microsoft.Resources/resourceGroups", 40 | "name": "[parameters('resourceGroupName')]", 41 | "location": "[parameters('resourceGroupLocation')]", 42 | "apiVersion": "2019-10-01" 43 | }, 44 | { 45 | "type": "Microsoft.Resources/deployments", 46 | "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", 47 | "resourceGroup": "[parameters('resourceGroupName')]", 48 | "apiVersion": "2019-10-01", 49 | "dependsOn": [ 50 | "[parameters('resourceGroupName')]" 51 | ], 52 | "properties": { 53 | "mode": "Incremental", 54 | "expressionEvaluationOptions": { 55 | "scope": "inner" 56 | }, 57 | "parameters": { 58 | "resourceGroupName": { 59 | "value": "[parameters('resourceGroupName')]" 60 | }, 61 | "resourceGroupLocation": { 62 | "value": "[parameters('resourceGroupLocation')]" 63 | }, 64 | "resourceName": { 65 | "value": "[parameters('resourceName')]" 66 | }, 67 | "resourceLocation": { 68 | "value": "[parameters('resourceLocation')]" 69 | } 70 | }, 71 | "template": { 72 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 73 | "contentVersion": "1.0.0.0", 74 | "parameters": { 75 | "resourceGroupName": { 76 | "type": "string" 77 | }, 78 | "resourceGroupLocation": { 79 | "type": "string" 80 | }, 81 | "resourceName": { 82 | "type": "string" 83 | }, 84 | "resourceLocation": { 85 | "type": "string" 86 | } 87 | }, 88 | "variables": { 89 | "storage_name": "[toLower(concat('storage', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId))))]", 90 | "appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", 91 | "storage_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Storage/storageAccounts/', variables('storage_name'))]", 92 | "appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]", 93 | "function_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/sites/', parameters('resourceName'))]" 94 | }, 95 | "resources": [ 96 | { 97 | "location": "[parameters('resourceLocation')]", 98 | "name": "[parameters('resourceName')]", 99 | "type": "Microsoft.Web/sites", 100 | "apiVersion": "2015-08-01", 101 | "tags": { 102 | "[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty" 103 | }, 104 | "dependsOn": [ 105 | "[variables('appServicePlan_ResourceId')]", 106 | "[variables('storage_ResourceId')]" 107 | ], 108 | "kind": "functionapp", 109 | "properties": { 110 | "name": "[parameters('resourceName')]", 111 | "kind": "functionapp", 112 | "httpsOnly": true, 113 | "reserved": false, 114 | "serverFarmId": "[variables('appServicePlan_ResourceId')]", 115 | "siteConfig": { 116 | "alwaysOn": true 117 | } 118 | }, 119 | "identity": { 120 | "type": "SystemAssigned" 121 | }, 122 | "resources": [ 123 | { 124 | "name": "appsettings", 125 | "type": "config", 126 | "apiVersion": "2015-08-01", 127 | "dependsOn": [ 128 | "[variables('function_ResourceId')]" 129 | ], 130 | "properties": { 131 | "AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storage_name'), ';AccountKey=', listKeys(variables('storage_ResourceId'), '2017-10-01').keys[0].value, ';EndpointSuffix=', 'core.windows.net')]", 132 | "FUNCTIONS_EXTENSION_VERSION": "~3", 133 | "FUNCTIONS_WORKER_RUNTIME": "dotnet" 134 | } 135 | } 136 | ] 137 | }, 138 | { 139 | "location": "[parameters('resourceGroupLocation')]", 140 | "name": "[variables('storage_name')]", 141 | "type": "Microsoft.Storage/storageAccounts", 142 | "apiVersion": "2017-10-01", 143 | "tags": { 144 | "[concat('hidden-related:', concat('/providers/Microsoft.Web/sites/', parameters('resourceName')))]": "empty" 145 | }, 146 | "properties": { 147 | "supportsHttpsTrafficOnly": true 148 | }, 149 | "sku": { 150 | "name": "Standard_LRS" 151 | }, 152 | "kind": "Storage" 153 | }, 154 | { 155 | "location": "[parameters('resourceGroupLocation')]", 156 | "name": "[variables('appServicePlan_name')]", 157 | "type": "Microsoft.Web/serverFarms", 158 | "apiVersion": "2015-08-01", 159 | "sku": { 160 | "name": "S1", 161 | "tier": "Standard", 162 | "family": "S", 163 | "size": "S1" 164 | }, 165 | "properties": { 166 | "name": "[variables('appServicePlan_name')]" 167 | } 168 | } 169 | ] 170 | } 171 | } 172 | } 173 | ] 174 | } -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.DeliveryTracker/Properties/ServiceDependencies/pizzaconftracker - Zip Deploy/signalr1.arm.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "resourceGroupName": { 6 | "type": "string", 7 | "defaultValue": "dotnetconf", 8 | "metadata": { 9 | "_parameterType": "resourceGroup", 10 | "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." 11 | } 12 | }, 13 | "resourceGroupLocation": { 14 | "type": "string", 15 | "defaultValue": "eastus", 16 | "metadata": { 17 | "_parameterType": "location", 18 | "description": "Location of the resource group. Resource groups could have different location than resources." 19 | } 20 | }, 21 | "resourceLocation": { 22 | "type": "string", 23 | "defaultValue": "[parameters('resourceGroupLocation')]", 24 | "metadata": { 25 | "_parameterType": "location", 26 | "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." 27 | } 28 | } 29 | }, 30 | "resources": [ 31 | { 32 | "type": "Microsoft.Resources/resourceGroups", 33 | "name": "[parameters('resourceGroupName')]", 34 | "location": "[parameters('resourceGroupLocation')]", 35 | "apiVersion": "2019-10-01" 36 | }, 37 | { 38 | "type": "Microsoft.Resources/deployments", 39 | "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat('pizzaconfdelivery', subscription().subscriptionId)))]", 40 | "resourceGroup": "[parameters('resourceGroupName')]", 41 | "apiVersion": "2019-10-01", 42 | "dependsOn": [ 43 | "[parameters('resourceGroupName')]" 44 | ], 45 | "properties": { 46 | "mode": "Incremental", 47 | "template": { 48 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 49 | "contentVersion": "1.0.0.0", 50 | "resources": [ 51 | { 52 | "sku": { 53 | "name": "Standard_S1", 54 | "tier": "Standard", 55 | "size": "S1", 56 | "capacity": 1 57 | }, 58 | "location": "[parameters('resourceLocation')]", 59 | "name": "pizzaconfdelivery", 60 | "type": "Microsoft.SignalRService/SignalR", 61 | "apiVersion": "2018-10-01" 62 | } 63 | ] 64 | } 65 | } 66 | } 67 | ], 68 | "metadata": { 69 | "_dependencyType": "signalr.function" 70 | } 71 | } -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.DeliveryTracker/Properties/ServiceDependencies/pizzaconftracker - Zip Deploy/storage1.arm.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "resourceGroupName": { 6 | "type": "string", 7 | "defaultValue": "dotnetconf", 8 | "metadata": { 9 | "_parameterType": "resourceGroup", 10 | "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." 11 | } 12 | }, 13 | "resourceGroupLocation": { 14 | "type": "string", 15 | "defaultValue": "eastus", 16 | "metadata": { 17 | "_parameterType": "location", 18 | "description": "Location of the resource group. Resource groups could have different location than resources." 19 | } 20 | }, 21 | "resourceLocation": { 22 | "type": "string", 23 | "defaultValue": "[parameters('resourceGroupLocation')]", 24 | "metadata": { 25 | "_parameterType": "location", 26 | "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." 27 | } 28 | } 29 | }, 30 | "resources": [ 31 | { 32 | "type": "Microsoft.Resources/resourceGroups", 33 | "name": "[parameters('resourceGroupName')]", 34 | "location": "[parameters('resourceGroupLocation')]", 35 | "apiVersion": "2019-10-01" 36 | }, 37 | { 38 | "type": "Microsoft.Resources/deployments", 39 | "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat('pizzaconf', subscription().subscriptionId)))]", 40 | "resourceGroup": "[parameters('resourceGroupName')]", 41 | "apiVersion": "2019-10-01", 42 | "dependsOn": [ 43 | "[parameters('resourceGroupName')]" 44 | ], 45 | "properties": { 46 | "mode": "Incremental", 47 | "template": { 48 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 49 | "contentVersion": "1.0.0.0", 50 | "resources": [ 51 | { 52 | "sku": { 53 | "name": "Standard_LRS", 54 | "tier": "Standard" 55 | }, 56 | "kind": "StorageV2", 57 | "name": "pizzaconf", 58 | "type": "Microsoft.Storage/storageAccounts", 59 | "location": "[parameters('resourceLocation')]", 60 | "apiVersion": "2017-10-01" 61 | } 62 | ] 63 | } 64 | } 65 | } 66 | ], 67 | "metadata": { 68 | "_dependencyType": "storage.azure" 69 | } 70 | } -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.DeliveryTracker/Properties/serviceDependencies.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "secrets1": { 4 | "type": "secrets" 5 | }, 6 | "appInsights1": { 7 | "type": "appInsights", 8 | "connectionId": "APPLICATIONINSIGHTS_CONNECTION_STRING" 9 | }, 10 | "storage1": { 11 | "type": "storage", 12 | "connectionId": "AzureWebJobsStorage" 13 | }, 14 | "signalr1": { 15 | "type": "signalr", 16 | "connectionId": "AzureSignalRConnectionString", 17 | "dynamicId": null 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.DeliveryTracker/Properties/serviceDependencies.local.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "appInsights1": { 4 | "type": "appInsights.sdk" 5 | }, 6 | "storage1": { 7 | "type": "storage.emulator", 8 | "connectionId": "AzureWebJobsStorage" 9 | }, 10 | "secrets1": { 11 | "type": "secrets.user" 12 | }, 13 | "signalr1": { 14 | "secretStore": "LocalSecretsFile", 15 | "resourceId": "/subscriptions/[parameters('subscriptionId')]/resourceGroups/[parameters('resourceGroupName')]/providers/Microsoft.SignalRService/SignalR/pizzaconfdelivery", 16 | "type": "signalr.function", 17 | "connectionId": "AzureSignalRConnectionString", 18 | "dynamicId": null 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.DeliveryTracker/Properties/serviceDependencies.pizzaconftracker - Zip Deploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "appInsights1": { 4 | "resourceId": "/subscriptions/[parameters('subscriptionId')]/resourceGroups/[parameters('resourceGroupName')]/providers/microsoft.insights/components/pizzaconf-insights", 5 | "type": "appInsights.azure", 6 | "connectionId": "APPLICATIONINSIGHTS_CONNECTION_STRING" 7 | }, 8 | "storage1": { 9 | "resourceId": "/subscriptions/[parameters('subscriptionId')]/resourceGroups/[parameters('resourceGroupName')]/providers/Microsoft.Storage/storageAccounts/pizzaconf", 10 | "type": "storage.azure", 11 | "connectionId": "AzureWebJobsStorage" 12 | }, 13 | "signalr1": { 14 | "secretStore": "AzureAppSettings", 15 | "resourceId": "/subscriptions/[parameters('subscriptionId')]/resourceGroups/[parameters('resourceGroupName')]/providers/Microsoft.SignalRService/SignalR/pizzaconfdelivery", 16 | "type": "signalr.function", 17 | "connectionId": "AzureSignalRConnectionString", 18 | "dynamicId": null 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.DeliveryTracker/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Azure.Identity; 3 | using Microsoft.Azure.Functions.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.Configuration; 5 | 6 | [assembly: FunctionsStartup(typeof(PizzaConf.DeliveryTracker.Startup))] 7 | 8 | namespace PizzaConf.DeliveryTracker; 9 | 10 | class Startup : FunctionsStartup 11 | { 12 | public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder) 13 | { 14 | string appConfigUrl = Environment.GetEnvironmentVariable("appConfigUrl") ?? ""; 15 | 16 | if (string.IsNullOrEmpty(appConfigUrl)) 17 | throw new NullReferenceException($"{nameof(appConfigUrl)} setting needs to be set to the Azure App Config url"); 18 | 19 | builder.ConfigurationBuilder.AddAzureAppConfiguration((options) => 20 | { 21 | options.Connect(new Uri(appConfigUrl), new DefaultAzureCredential()) 22 | .ConfigureKeyVault(kvOptions => kvOptions.SetCredential(new DefaultAzureCredential())); 23 | }); 24 | } 25 | 26 | public override void Configure(IFunctionsHostBuilder builder) 27 | { 28 | } 29 | } -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.DeliveryTracker/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "logging": { 4 | "applicationInsights": { 5 | "samplingSettings": { 6 | "isEnabled": true, 7 | "excludedTypes": "Request" 8 | } 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Menu.Api/Data/DbInitializer.cs: -------------------------------------------------------------------------------- 1 | using PizzaConf.Models; 2 | 3 | namespace PizzaConf.Menu.Api.Data; 4 | 5 | public static class DbInitializer 6 | { 7 | public static void Initialize(PizzaContext context) 8 | { 9 | if (context.Pizzas.Any()) 10 | return; 11 | 12 | var cheese = new Pizza { Name = "Lotsa Mozza", Description = "The best cheese pizza in the world", ImageUrl = "pizza1.jpg" }; 13 | var pepp = new Pizza { Name = "Put some pep in your step", Description = "Seriously good pepporoni", ImageUrl = "pizza2.jpg" }; 14 | var at = new Pizza { Name = "Don't at me", Description = "Pineapple on a pizza", ImageUrl = "pizza3.jpg" }; 15 | var forest = new Pizza { Name = "Forest floor", Description = "Pineapple on a pizza", ImageUrl = "pizza4.jpg" }; 16 | 17 | context.Add(cheese); 18 | context.Add(pepp); 19 | context.Add(at); 20 | context.Add(forest); 21 | 22 | context.SaveChanges(); 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Menu.Api/Data/PizzaContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using PizzaConf.Models; 3 | 4 | namespace PizzaConf.Menu.Api.Data; 5 | 6 | public class PizzaContext : DbContext 7 | { 8 | public PizzaContext(DbContextOptions options) : base(options) { } 9 | 10 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 11 | { 12 | optionsBuilder.LogTo(Console.WriteLine); 13 | } 14 | 15 | public DbSet Pizzas => Set(); 16 | } 17 | 18 | public static class Extensions 19 | { 20 | public static void CreateDbIfNotExists(this IHost host) 21 | { 22 | using var scope = host.Services.CreateScope(); 23 | 24 | var services = scope.ServiceProvider; 25 | var context = services.GetRequiredService(); 26 | context.Database.EnsureCreated(); 27 | DbInitializer.Initialize(context); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Menu.Api/Data/StorageInitializer.cs: -------------------------------------------------------------------------------- 1 | using Azure.Identity; 2 | using Azure.Storage.Blobs; 3 | using Azure.Storage.Blobs.Models; 4 | 5 | namespace PizzaConf.Menu.Api.Data; 6 | 7 | public static class StorageInitializer 8 | { 9 | public static async Task UploadImages(this IHost host, string? storageUrl) 10 | { 11 | if (string.IsNullOrEmpty(storageUrl)) 12 | return; 13 | 14 | BlobContainerClient containerClient = new BlobContainerClient(new Uri(storageUrl), new DefaultAzureCredential()); 15 | 16 | foreach (var imageFileName in Directory.GetFiles("media")) 17 | { 18 | try 19 | { 20 | var imageClient = containerClient.GetBlobClient(imageFileName); 21 | 22 | var blobExists = (await imageClient.ExistsAsync()).Value; 23 | 24 | if (!blobExists) 25 | await imageClient.UploadAsync(imageFileName, overwrite: false); 26 | } 27 | catch (Exception ex) 28 | { 29 | System.Diagnostics.Debug.WriteLine(ex); 30 | } 31 | } 32 | 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Menu.Api/Dockerfile: -------------------------------------------------------------------------------- 1 | #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. 2 | 3 | FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base 4 | WORKDIR /app 5 | EXPOSE 80 6 | EXPOSE 443 7 | 8 | FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build 9 | WORKDIR /src 10 | COPY ["PizzaConf.Menu.Api/PizzaConf.Menu.Api.csproj", "PizzaConf.Menu.Api/"] 11 | COPY ["PizzaConf.Models/PizzaConf.Models.csproj", "PizzaConf.Models/"] 12 | RUN dotnet restore "PizzaConf.Menu.Api/PizzaConf.Menu.Api.csproj" 13 | COPY . . 14 | WORKDIR "/src/PizzaConf.Menu.Api" 15 | RUN dotnet build "PizzaConf.Menu.Api.csproj" -c Release -o /app/build 16 | 17 | FROM build AS publish 18 | RUN dotnet publish "PizzaConf.Menu.Api.csproj" -c Release -o /app/publish /p:UseAppHost=false 19 | 20 | FROM base AS final 21 | WORKDIR /app 22 | COPY --from=publish /app/publish . 23 | ENTRYPOINT ["dotnet", "PizzaConf.Menu.Api.dll"] -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Menu.Api/PizzaConf.Menu.Api.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0 5 | enable 6 | enable 7 | a6603504-d3a2-4168-be9f-e656cc546af5 8 | Linux 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | all 31 | runtime; build; native; contentfiles; analyzers; buildtransitive 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Menu.Api/Program.cs: -------------------------------------------------------------------------------- 1 | using Azure.Identity; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.EntityFrameworkCore; 4 | using PizzaConf.Menu.Api.Data; 5 | using PizzaConf.Menu.Api.Services; 6 | using PizzaConf.Models; 7 | 8 | var builder = WebApplication.CreateBuilder(args); 9 | 10 | // Add services to the container. 11 | // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle 12 | builder.Services.AddEndpointsApiExplorer(); 13 | builder.Services.AddSwaggerGen(); 14 | 15 | builder.Configuration.AddAzureAppConfiguration((options) => 16 | { 17 | string? appConfigUri = builder.Configuration["appConfigUrl"]; 18 | if (appConfigUri == null) 19 | throw new NullReferenceException($"{nameof(appConfigUri)} setting needs to have the Azure App Config url set."); 20 | 21 | options.Connect(new Uri(appConfigUri), new DefaultAzureCredential()) 22 | .Select("menuDb") 23 | .ConfigureKeyVault(options => options.SetCredential(new DefaultAzureCredential())); 24 | }); 25 | 26 | builder.Services 27 | .AddSqlServer(builder.Configuration["menuDb"] ?? "Server=(localdb)\\mssqllocaldb;Database=MenuContext-0e9;Trusted_Connection=True;MultipleActiveResultSets=true", 28 | (options) => options.EnableRetryOnFailure()); 29 | 30 | builder.Services.AddTransient(); 31 | 32 | var app = builder.Build(); 33 | 34 | // Configure the HTTP request pipeline. 35 | if (app.Environment.IsDevelopment()) 36 | { 37 | app.UseSwagger(); 38 | app.UseSwaggerUI(); 39 | } 40 | 41 | app.UseHttpsRedirection(); 42 | 43 | 44 | app.MapGet("/pizzas", async ([FromServices]PizzaService pizzaService) => 45 | { 46 | var pizzas = await pizzaService.GetPizzas(); 47 | 48 | return Results.Ok(pizzas); 49 | }) 50 | .WithName("GetAllPizzas") 51 | .WithOpenApi() 52 | .Produces>(StatusCodes.Status200OK); 53 | 54 | app.MapGet("/pizzas/{id}", async (int id, [FromServices]PizzaService pizzaService) => 55 | { 56 | var pizza = await pizzaService.GetPizzaById(id); 57 | 58 | if (pizza == null) 59 | return Results.NotFound(); 60 | else 61 | return Results.Ok(pizza); 62 | }) 63 | .WithName("GetIndividualPizza") 64 | .WithOpenApi() 65 | .Produces(StatusCodes.Status404NotFound) 66 | .Produces(StatusCodes.Status200OK); 67 | 68 | app.CreateDbIfNotExists(); 69 | await app.UploadImages(builder.Configuration["imageStorageUrl"]); 70 | 71 | app.Run(); 72 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Menu.Api/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "http": { 4 | "commandName": "Project", 5 | "launchBrowser": true, 6 | "launchUrl": "swagger", 7 | "environmentVariables": { 8 | "ASPNETCORE_ENVIRONMENT": "Development" 9 | }, 10 | "dotnetRunMessages": true, 11 | "applicationUrl": "http://localhost:5249" 12 | }, 13 | "https": { 14 | "commandName": "Project", 15 | "launchBrowser": true, 16 | "launchUrl": "swagger", 17 | "environmentVariables": { 18 | "ASPNETCORE_ENVIRONMENT": "Development" 19 | }, 20 | "dotnetRunMessages": true, 21 | "applicationUrl": "https://localhost:7180;http://localhost:5249" 22 | }, 23 | "IIS Express": { 24 | "commandName": "IISExpress", 25 | "launchBrowser": true, 26 | "launchUrl": "swagger", 27 | "environmentVariables": { 28 | "ASPNETCORE_ENVIRONMENT": "Development" 29 | } 30 | }, 31 | "Docker": { 32 | "commandName": "Docker", 33 | "launchBrowser": true, 34 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", 35 | "publishAllPorts": true, 36 | "useSSL": true 37 | } 38 | }, 39 | "$schema": "https://json.schemastore.org/launchsettings.json", 40 | "iisSettings": { 41 | "windowsAuthentication": false, 42 | "anonymousAuthentication": true, 43 | "iisExpress": { 44 | "applicationUrl": "http://localhost:17625", 45 | "sslPort": 44313 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Menu.Api/Services/PizzaService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using PizzaConf.Menu.Api.Data; 3 | using PizzaConf.Models; 4 | 5 | namespace PizzaConf.Menu.Api.Services; 6 | 7 | public class PizzaService 8 | { 9 | private readonly PizzaContext _context; 10 | 11 | public PizzaService(PizzaContext context) 12 | { 13 | _context = context; 14 | } 15 | 16 | public async Task> GetPizzas() 17 | { 18 | return await _context.Pizzas.AsNoTracking().ToListAsync(); 19 | } 20 | 21 | public async Task GetPizzaById(int id) 22 | { 23 | var pizza = await _context.Pizzas.FindAsync(id); 24 | 25 | return pizza; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Menu.Api/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "appConfigUrl": "https://pizzaconfconfig.azconfig.io" 9 | } 10 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Menu.Api/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Menu.Api/media/order1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codemillmatt/dotnetconfpizza/ce67bca5205fab00b822a733c22d2e3e331e3880/PizzaConf/PizzaConf.Menu.Api/media/order1.jpg -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Menu.Api/media/order2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codemillmatt/dotnetconfpizza/ce67bca5205fab00b822a733c22d2e3e331e3880/PizzaConf/PizzaConf.Menu.Api/media/order2.jpg -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Menu.Api/media/order3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codemillmatt/dotnetconfpizza/ce67bca5205fab00b822a733c22d2e3e331e3880/PizzaConf/PizzaConf.Menu.Api/media/order3.jpg -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Menu.Api/media/order4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codemillmatt/dotnetconfpizza/ce67bca5205fab00b822a733c22d2e3e331e3880/PizzaConf/PizzaConf.Menu.Api/media/order4.jpg -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Menu.Api/media/pizza.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codemillmatt/dotnetconfpizza/ce67bca5205fab00b822a733c22d2e3e331e3880/PizzaConf/PizzaConf.Menu.Api/media/pizza.jpg -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Menu.Api/media/pizza1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codemillmatt/dotnetconfpizza/ce67bca5205fab00b822a733c22d2e3e331e3880/PizzaConf/PizzaConf.Menu.Api/media/pizza1.jpg -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Menu.Api/media/pizza2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codemillmatt/dotnetconfpizza/ce67bca5205fab00b822a733c22d2e3e331e3880/PizzaConf/PizzaConf.Menu.Api/media/pizza2.jpg -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Menu.Api/media/pizza3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codemillmatt/dotnetconfpizza/ce67bca5205fab00b822a733c22d2e3e331e3880/PizzaConf/PizzaConf.Menu.Api/media/pizza3.jpg -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Menu.Api/media/pizza4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codemillmatt/dotnetconfpizza/ce67bca5205fab00b822a733c22d2e3e331e3880/PizzaConf/PizzaConf.Menu.Api/media/pizza4.jpg -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Models/OrderedPizza.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace PizzaConf.Models; 4 | 5 | public class OrderedPizza 6 | { 7 | public int Id { get; set; } 8 | 9 | [Required] 10 | public string? Name { get; set; } 11 | 12 | 13 | [Required] 14 | public string? PizzaDescription { get; set; } 15 | 16 | [Required] 17 | public DateTime OrderedDate { get; set; } 18 | } 19 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Models/Pizza.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace PizzaConf.Models; 4 | 5 | public class Pizza 6 | { 7 | 8 | public int Id { get; set; } 9 | 10 | [Required] 11 | public string? Name { get; set; } 12 | 13 | [Required] 14 | public string? Description { get; set; } 15 | 16 | [Required] 17 | public string? ImageUrl { get; set; } 18 | } 19 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Models/PizzaConf.Models.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Models/TrackingMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace PizzaConf.Models 8 | { 9 | public class TrackingMessage 10 | { 11 | public string? StatusUrl { get; set; } 12 | public string? Status { get; set; } 13 | 14 | public int OrderId { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/App.razor: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | Not found 8 | 9 |

Sorry, there's nothing at this address.

10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/Configuration/DaprAppId.cs: -------------------------------------------------------------------------------- 1 | namespace PizzaConf.Web.Configuration 2 | { 3 | public class DaprAppId 4 | { 5 | public string? MenuApi { get; set; } 6 | public string? CheckoutApi { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/Data/CartWebService.cs: -------------------------------------------------------------------------------- 1 | using PizzaConf.Models; 2 | 3 | namespace PizzaConf.Web.Data; 4 | 5 | public class CartWebService 6 | { 7 | private readonly HttpClient _httpClient; 8 | 9 | public CartWebService (HttpClient httpClient) 10 | { 11 | _httpClient = httpClient; 12 | } 13 | 14 | public async Task?> GetCartContents() 15 | { 16 | string url = "/cart"; 17 | 18 | var contents = await _httpClient.GetFromJsonAsync>(url); 19 | 20 | return contents; 21 | } 22 | 23 | public async Task AddPizzaToOrder(string name, string description) 24 | { 25 | OrderedPizza pizza = new() { Name = name, PizzaDescription = description, OrderedDate = DateTime.Now }; 26 | 27 | string url = "/order"; 28 | 29 | await _httpClient.PostAsJsonAsync(url, pizza); 30 | } 31 | 32 | public async Task PlaceOrder() 33 | { 34 | string url = "/cart"; 35 | 36 | await _httpClient.DeleteAsync(url); 37 | 38 | return Random.Shared.Next(0, 100); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/Data/PizzaWebService.cs: -------------------------------------------------------------------------------- 1 | using PizzaConf.Models; 2 | 3 | namespace PizzaConf.Web.Data; 4 | 5 | public class PizzaWebService 6 | { 7 | private readonly HttpClient _httpClient; 8 | 9 | public PizzaWebService(HttpClient client) 10 | { 11 | _httpClient = client; 12 | } 13 | 14 | public async Task?> GetMenu() 15 | { 16 | var allThePizzas = await _httpClient.GetFromJsonAsync?>("/pizzas"); 17 | 18 | return allThePizzas; 19 | } 20 | 21 | public async Task GetPizza(int pizzaId) 22 | { 23 | var url = $"/pizzas/{pizzaId}"; 24 | 25 | var thePizza = await _httpClient.GetFromJsonAsync(url); 26 | 27 | return thePizza; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/Dockerfile: -------------------------------------------------------------------------------- 1 | #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. 2 | 3 | FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base 4 | WORKDIR /app 5 | EXPOSE 80 6 | EXPOSE 443 7 | 8 | FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build 9 | WORKDIR /src 10 | COPY ["PizzaConf.Web/PizzaConf.Web.csproj", "PizzaConf.Web/"] 11 | COPY ["PizzaConf.Models/PizzaConf.Models.csproj", "PizzaConf.Models/"] 12 | RUN dotnet restore "PizzaConf.Web/PizzaConf.Web.csproj" 13 | COPY . . 14 | WORKDIR "/src/PizzaConf.Web" 15 | RUN dotnet build "PizzaConf.Web.csproj" -c Release -o /app/build 16 | 17 | FROM build AS publish 18 | RUN dotnet publish "PizzaConf.Web.csproj" -c Release -o /app/publish /p:UseAppHost=false 19 | 20 | FROM base AS final 21 | WORKDIR /app 22 | COPY --from=publish /app/publish . 23 | ENTRYPOINT ["dotnet", "PizzaConf.Web.dll"] -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/Pages/Cart.razor: -------------------------------------------------------------------------------- 1 | @page "/cart" 2 | 3 | @using PizzaConf.Models 4 | @using PizzaConf.Web.Data 5 | 6 | @inject CartWebService cartService 7 | @inject NavigationManager navigation 8 | 9 | Your Pizzas 10 | 11 | @if (Pizzas == null || Pizzas.Count() == 0) 12 | { 13 |

The cart is empty - let's add some pizza!

14 | } 15 | else 16 | { 17 |

Here are your pizzas

18 | 19 |
    20 | @foreach (var pizza in Pizzas) 21 | { 22 |
  • @pizza.Name
  • 23 | } 24 |
25 | 26 |
27 | 28 |
29 | 30 | } 31 | 32 | @code { 33 | public IEnumerable? Pizzas; 34 | 35 | protected override async Task OnInitializedAsync() 36 | { 37 | Pizzas = await cartService.GetCartContents(); 38 | } 39 | 40 | private async Task PlaceOrder() 41 | { 42 | var orderId = await cartService.PlaceOrder(); 43 | 44 | navigation.NavigateTo($"/tracking/{orderId}"); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/Pages/Error.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model PizzaConf.Web.Pages.ErrorModel 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Error 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Error.

19 |

An error occurred while processing your request.

20 | 21 | @if (Model.ShowRequestId) 22 | { 23 |

24 | Request ID: @Model.RequestId 25 |

26 | } 27 | 28 |

Development Mode

29 |

30 | Swapping to the Development environment displays detailed information about the error that occurred. 31 |

32 |

33 | The Development environment shouldn't be enabled for deployed applications. 34 | It can result in displaying sensitive information from exceptions to end users. 35 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development 36 | and restarting the app. 37 |

38 |
39 |
40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/Pages/Error.cshtml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Microsoft.AspNetCore.Mvc.RazorPages; 3 | using System.Diagnostics; 4 | 5 | namespace PizzaConf.Web.Pages 6 | { 7 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] 8 | [IgnoreAntiforgeryToken] 9 | public class ErrorModel : PageModel 10 | { 11 | public string? RequestId { get; set; } 12 | 13 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 14 | 15 | private readonly ILogger _logger; 16 | 17 | public ErrorModel(ILogger logger) 18 | { 19 | _logger = logger; 20 | } 21 | 22 | public void OnGet() 23 | { 24 | RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/Pages/PizzaDetails.razor: -------------------------------------------------------------------------------- 1 | @page "/pizzadetails/{Id:int}" 2 | 3 | @using PizzaConf.Web.Data 4 | @using PizzaConf.Models 5 | 6 | @inject PizzaWebService pizzaService 7 | @inject CartWebService cartService 8 | @inject NavigationManager navigation 9 | 10 | @inject IConfiguration configuration 11 | 12 | Pizza Details 13 | 14 | @if (pizza == null) 15 | { 16 |

Loading...

17 | } 18 | else 19 | { 20 |

@pizza.Name

21 |

22 | OH MY GOODNESS! 23 |

24 | 25 |
26 | 27 | @pizza.Description 28 |

29 | 30 | } 31 | 32 | 33 | 34 | @code { 35 | 36 | [Parameter] 37 | public int Id { get; set; } 38 | 39 | private string? cdnUrl; 40 | 41 | private Pizza? pizza; 42 | 43 | protected override async Task OnInitializedAsync() 44 | { 45 | cdnUrl = configuration.GetValue("cdnUrl"); 46 | 47 | pizza = await pizzaService.GetPizza(Id); 48 | 49 | pizza.ImageUrl = $"{cdnUrl}/pizzaimages/{pizza.ImageUrl}"; 50 | } 51 | 52 | private async Task AddToOrder() 53 | { 54 | await cartService.AddPizzaToOrder(pizza.Name, pizza.Description); 55 | 56 | navigation.NavigateTo("cart"); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/Pages/PizzaMenu.razor: -------------------------------------------------------------------------------- 1 | @page "/" 2 | @using PizzaConf.Web.Data 3 | @using PizzaConf.Models 4 | @inject PizzaWebService pizzaService 5 | @inject NavigationManager navigation 6 | 7 | Pizza Conf Menu 8 | 9 |

Pizza Conf Menu

10 | 11 |

Here is our delicious menu

12 | 13 | @if (pizzas == null) 14 | { 15 |

Loading...

16 | } 17 | else 18 | { 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | @foreach (var pizza in pizzas) 28 | { 29 | 30 | 35 | 36 | 37 | } 38 | 39 |
NameDescription
31 | 32 | @pizza.Name 33 | 34 | @pizza.Description
40 | } 41 | 42 | @code { 43 | private IEnumerable? pizzas; 44 | 45 | protected override async Task OnInitializedAsync() 46 | { 47 | pizzas = await pizzaService.GetMenu(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/Pages/Tracking.razor: -------------------------------------------------------------------------------- 1 | @page "/tracking/{OrderId:int}" 2 | 3 | @using PizzaConf.Models 4 | @using PizzaConf.Web.Data 5 | @using Microsoft.AspNetCore.SignalR.Client 6 | 7 | @inject IConfiguration configuration 8 | 9 |

Where's My Order?

10 | 11 | 12 |
@OrderStatus
13 | 14 | @code { 15 | [Parameter] 16 | public int OrderId { get; set; } 17 | 18 | public string? OrderStatusUrl { get; set; } = "https://pizzaconf.azureedge.net/pizzaimages/pizza1.jpg"; 19 | public string? OrderStatus { get; set; } = "Waiting for transmission..."; 20 | 21 | HubConnection? hubConnection; 22 | 23 | string cdnUrl; 24 | 25 | protected override async Task OnInitializedAsync() 26 | { 27 | cdnUrl = configuration.GetValue("cdnUrl"); 28 | 29 | if (hubConnection != null && hubConnection.State == HubConnectionState.Connected) 30 | await hubConnection.StopAsync(); 31 | 32 | hubConnection = new HubConnectionBuilder() 33 | .WithUrl(configuration["trackingUrl"]) 34 | .WithAutomaticReconnect() 35 | .Build(); 36 | 37 | hubConnection.On("newMessage", (obj) => 38 | { 39 | OrderStatusUrl = $"{cdnUrl}/pizzaimages/{obj.StatusUrl}"; 40 | OrderStatus = obj.Status; 41 | StateHasChanged(); 42 | }); 43 | 44 | await hubConnection.StartAsync(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/Pages/_Host.cshtml: -------------------------------------------------------------------------------- 1 | @page "/" 2 | @using Microsoft.AspNetCore.Components.Web 3 | @namespace PizzaConf.Web.Pages 4 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | An error has occurred. This application may no longer respond until reloaded. 24 | 25 | 26 | An unhandled exception has occurred. See browser dev tools for details. 27 | 28 | Reload 29 | 🗙 30 |
31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/PizzaConf.Web.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | enable 6 | enable 7 | 8a585468-b3bc-42f4-92df-f0be9c8f7033 8 | Linux 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/Program.cs: -------------------------------------------------------------------------------- 1 | using Azure.Identity; 2 | using Microsoft.AspNetCore.Components; 3 | using Microsoft.AspNetCore.Components.Web; 4 | using PizzaConf.Web.Data; 5 | 6 | using Microsoft.Extensions.Configuration.AzureAppConfiguration; 7 | using PizzaConf.Web.Configuration; 8 | 9 | var builder = WebApplication.CreateBuilder(args); 10 | 11 | // Add services to the container. 12 | builder.Services.AddRazorPages(); 13 | builder.Services.AddServerSideBlazor(); 14 | builder.Services.AddSingleton(); 15 | builder.Services.AddSingleton(); 16 | 17 | builder.Configuration.AddAzureAppConfiguration((options) => 18 | { 19 | string? appConfigUrl = builder.Configuration["appConfigUrl"] ?? ""; 20 | if (string.IsNullOrEmpty(appConfigUrl)) 21 | throw new NullReferenceException($"{nameof(appConfigUrl)} needs to be set to the value of the Azure App Config url"); 22 | 23 | // Make sure it doesn't blow up because it doesn't have access to key vault 24 | options.Connect(new Uri(appConfigUrl), new DefaultAzureCredential()) 25 | .Select("cartUrl").Select("menuUrl").Select("trackingUrl").Select("DaprAppId*").Select("cdnUrl") 26 | .ConfigureKeyVault(options => new DefaultAzureCredential()); 27 | }); 28 | 29 | var daprIds = builder.Configuration.GetSection("DaprAppId:PizzaConf").Get(); 30 | 31 | builder.Services.AddHttpClient(client => 32 | { 33 | string url = builder.Configuration["menuUrl"] ?? "http://localhost:3500"; 34 | Uri baseAddress = new(url); 35 | 36 | if (!string.IsNullOrEmpty(daprIds?.MenuApi)) 37 | { 38 | client.DefaultRequestHeaders.Add("dapr-app-id", daprIds.MenuApi); 39 | } 40 | 41 | client.BaseAddress = baseAddress; 42 | }); 43 | 44 | builder.Services.AddHttpClient(client => 45 | { 46 | string url = builder.Configuration["cartUrl"] ?? "http://localhost:3500"; 47 | Uri baseAddress = new(url); 48 | 49 | if (!string.IsNullOrEmpty(daprIds?.CheckoutApi)) 50 | { 51 | client.DefaultRequestHeaders.Add("dapr-app-id", daprIds.CheckoutApi); 52 | } 53 | 54 | client.BaseAddress = baseAddress; 55 | }); 56 | 57 | var app = builder.Build(); 58 | 59 | // Configure the HTTP request pipeline. 60 | if (!app.Environment.IsDevelopment()) 61 | { 62 | app.UseExceptionHandler("/Error"); 63 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. 64 | app.UseHsts(); 65 | } 66 | 67 | app.UseHttpsRedirection(); 68 | 69 | app.UseStaticFiles(); 70 | 71 | app.UseRouting(); 72 | 73 | app.MapBlazorHub(); 74 | app.MapFallbackToPage("/_Host"); 75 | 76 | app.Run(); 77 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "http": { 4 | "commandName": "Project", 5 | "launchBrowser": true, 6 | "environmentVariables": { 7 | "ASPNETCORE_ENVIRONMENT": "Development" 8 | }, 9 | "dotnetRunMessages": true, 10 | "applicationUrl": "http://localhost:5168" 11 | }, 12 | "https": { 13 | "commandName": "Project", 14 | "launchBrowser": true, 15 | "environmentVariables": { 16 | "ASPNETCORE_ENVIRONMENT": "Development" 17 | }, 18 | "dotnetRunMessages": true, 19 | "applicationUrl": "https://localhost:7016;http://localhost:5168" 20 | }, 21 | "IIS Express": { 22 | "commandName": "IISExpress", 23 | "launchBrowser": true, 24 | "environmentVariables": { 25 | "ASPNETCORE_ENVIRONMENT": "Development" 26 | } 27 | }, 28 | "Docker": { 29 | "commandName": "Docker", 30 | "launchBrowser": true, 31 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}", 32 | "publishAllPorts": true, 33 | "useSSL": true 34 | } 35 | }, 36 | "iisSettings": { 37 | "windowsAuthentication": false, 38 | "anonymousAuthentication": true, 39 | "iisExpress": { 40 | "applicationUrl": "http://localhost:61818", 41 | "sslPort": 44359 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/Shared/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @inherits LayoutComponentBase 2 | 3 | Pizza Conf 4 | 5 |
6 | 9 | 10 |
11 |
12 | About 13 |
14 | 15 |
16 | @Body 17 |
18 |
19 |
20 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/Shared/MainLayout.razor.css: -------------------------------------------------------------------------------- 1 | .page { 2 | position: relative; 3 | display: flex; 4 | flex-direction: column; 5 | } 6 | 7 | main { 8 | flex: 1; 9 | } 10 | 11 | .sidebar { 12 | background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); 13 | } 14 | 15 | .top-row { 16 | background-color: #f7f7f7; 17 | border-bottom: 1px solid #d6d5d5; 18 | justify-content: flex-end; 19 | height: 3.5rem; 20 | display: flex; 21 | align-items: center; 22 | } 23 | 24 | .top-row ::deep a, .top-row .btn-link { 25 | white-space: nowrap; 26 | margin-left: 1.5rem; 27 | } 28 | 29 | .top-row a:first-child { 30 | overflow: hidden; 31 | text-overflow: ellipsis; 32 | } 33 | 34 | @media (max-width: 640.98px) { 35 | .top-row:not(.auth) { 36 | display: none; 37 | } 38 | 39 | .top-row.auth { 40 | justify-content: space-between; 41 | } 42 | 43 | .top-row a, .top-row .btn-link { 44 | margin-left: 0; 45 | } 46 | } 47 | 48 | @media (min-width: 641px) { 49 | .page { 50 | flex-direction: row; 51 | } 52 | 53 | .sidebar { 54 | width: 250px; 55 | height: 100vh; 56 | position: sticky; 57 | top: 0; 58 | } 59 | 60 | .top-row { 61 | position: sticky; 62 | top: 0; 63 | z-index: 1; 64 | } 65 | 66 | .top-row, article { 67 | padding-left: 2rem !important; 68 | padding-right: 1.5rem !important; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/Shared/NavMenu.razor: -------------------------------------------------------------------------------- 1 |  9 | 10 | 24 | 25 | @code { 26 | private bool collapseNavMenu = true; 27 | 28 | private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null; 29 | 30 | private void ToggleNavMenu() 31 | { 32 | collapseNavMenu = !collapseNavMenu; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/Shared/NavMenu.razor.css: -------------------------------------------------------------------------------- 1 | .navbar-toggler { 2 | background-color: rgba(255, 255, 255, 0.1); 3 | } 4 | 5 | .top-row { 6 | height: 3.5rem; 7 | background-color: rgba(0,0,0,0.4); 8 | } 9 | 10 | .navbar-brand { 11 | font-size: 1.1rem; 12 | } 13 | 14 | .oi { 15 | width: 2rem; 16 | font-size: 1.1rem; 17 | vertical-align: text-top; 18 | top: -2px; 19 | } 20 | 21 | .nav-item { 22 | font-size: 0.9rem; 23 | padding-bottom: 0.5rem; 24 | } 25 | 26 | .nav-item:first-of-type { 27 | padding-top: 1rem; 28 | } 29 | 30 | .nav-item:last-of-type { 31 | padding-bottom: 1rem; 32 | } 33 | 34 | .nav-item ::deep a { 35 | color: #d7d7d7; 36 | border-radius: 4px; 37 | height: 3rem; 38 | display: flex; 39 | align-items: center; 40 | line-height: 3rem; 41 | } 42 | 43 | .nav-item ::deep a.active { 44 | background-color: rgba(255,255,255,0.25); 45 | color: white; 46 | } 47 | 48 | .nav-item ::deep a:hover { 49 | background-color: rgba(255,255,255,0.1); 50 | color: white; 51 | } 52 | 53 | @media (min-width: 641px) { 54 | .navbar-toggler { 55 | display: none; 56 | } 57 | 58 | .collapse { 59 | /* Never collapse the sidebar for wide screens */ 60 | display: block; 61 | } 62 | 63 | .nav-scrollable { 64 | /* Allow sidebar to scroll for tall menus */ 65 | height: calc(100vh - 3.5rem); 66 | overflow-y: auto; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using Microsoft.AspNetCore.Authorization 3 | @using Microsoft.AspNetCore.Components.Authorization 4 | @using Microsoft.AspNetCore.Components.Forms 5 | @using Microsoft.AspNetCore.Components.Routing 6 | @using Microsoft.AspNetCore.Components.Web 7 | @using Microsoft.AspNetCore.Components.Web.Virtualization 8 | @using Microsoft.JSInterop 9 | @using PizzaConf.Web 10 | @using PizzaConf.Web.Shared 11 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "DetailedErrors": true, 3 | "Logging": { 4 | "LogLevel": { 5 | "Default": "Information", 6 | "Microsoft.AspNetCore": "Warning" 7 | } 8 | }, 9 | "appConfigUrl": "https://appcs-yia43r5wlk54y.azconfig.io" 10 | } 11 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/wwwroot/css/open-iconic/FONT-LICENSE: -------------------------------------------------------------------------------- 1 | SIL OPEN FONT LICENSE Version 1.1 2 | 3 | Copyright (c) 2014 Waybury 4 | 5 | PREAMBLE 6 | The goals of the Open Font License (OFL) are to stimulate worldwide 7 | development of collaborative font projects, to support the font creation 8 | efforts of academic and linguistic communities, and to provide a free and 9 | open framework in which fonts may be shared and improved in partnership 10 | with others. 11 | 12 | The OFL allows the licensed fonts to be used, studied, modified and 13 | redistributed freely as long as they are not sold by themselves. The 14 | fonts, including any derivative works, can be bundled, embedded, 15 | redistributed and/or sold with any software provided that any reserved 16 | names are not used by derivative works. The fonts and derivatives, 17 | however, cannot be released under any other type of license. The 18 | requirement for fonts to remain under this license does not apply 19 | to any document created using the fonts or their derivatives. 20 | 21 | DEFINITIONS 22 | "Font Software" refers to the set of files released by the Copyright 23 | Holder(s) under this license and clearly marked as such. This may 24 | include source files, build scripts and documentation. 25 | 26 | "Reserved Font Name" refers to any names specified as such after the 27 | copyright statement(s). 28 | 29 | "Original Version" refers to the collection of Font Software components as 30 | distributed by the Copyright Holder(s). 31 | 32 | "Modified Version" refers to any derivative made by adding to, deleting, 33 | or substituting -- in part or in whole -- any of the components of the 34 | Original Version, by changing formats or by porting the Font Software to a 35 | new environment. 36 | 37 | "Author" refers to any designer, engineer, programmer, technical 38 | writer or other person who contributed to the Font Software. 39 | 40 | PERMISSION & CONDITIONS 41 | Permission is hereby granted, free of charge, to any person obtaining 42 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 43 | redistribute, and sell modified and unmodified copies of the Font 44 | Software, subject to the following conditions: 45 | 46 | 1) Neither the Font Software nor any of its individual components, 47 | in Original or Modified Versions, may be sold by itself. 48 | 49 | 2) Original or Modified Versions of the Font Software may be bundled, 50 | redistributed and/or sold with any software, provided that each copy 51 | contains the above copyright notice and this license. These can be 52 | included either as stand-alone text files, human-readable headers or 53 | in the appropriate machine-readable metadata fields within text or 54 | binary files as long as those fields can be easily viewed by the user. 55 | 56 | 3) No Modified Version of the Font Software may use the Reserved Font 57 | Name(s) unless explicit written permission is granted by the corresponding 58 | Copyright Holder. This restriction only applies to the primary font name as 59 | presented to the users. 60 | 61 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 62 | Software shall not be used to promote, endorse or advertise any 63 | Modified Version, except to acknowledge the contribution(s) of the 64 | Copyright Holder(s) and the Author(s) or with their explicit written 65 | permission. 66 | 67 | 5) The Font Software, modified or unmodified, in part or in whole, 68 | must be distributed entirely under this license, and must not be 69 | distributed under any other license. The requirement for fonts to 70 | remain under this license does not apply to any document created 71 | using the Font Software. 72 | 73 | TERMINATION 74 | This license becomes null and void if any of the above conditions are 75 | not met. 76 | 77 | DISCLAIMER 78 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 79 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 80 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 81 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 82 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 83 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 84 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 85 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 86 | OTHER DEALINGS IN THE FONT SOFTWARE. 87 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/wwwroot/css/open-iconic/ICON-LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Waybury 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/wwwroot/css/open-iconic/README.md: -------------------------------------------------------------------------------- 1 | [Open Iconic v1.1.1](http://useiconic.com/open) 2 | =========== 3 | 4 | ### Open Iconic is the open source sibling of [Iconic](http://useiconic.com). It is a hyper-legible collection of 223 icons with a tiny footprint—ready to use with Bootstrap and Foundation. [View the collection](http://useiconic.com/open#icons) 5 | 6 | 7 | 8 | ## What's in Open Iconic? 9 | 10 | * 223 icons designed to be legible down to 8 pixels 11 | * Super-light SVG files - 61.8 for the entire set 12 | * SVG sprite—the modern replacement for icon fonts 13 | * Webfont (EOT, OTF, SVG, TTF, WOFF), PNG and WebP formats 14 | * Webfont stylesheets (including versions for Bootstrap and Foundation) in CSS, LESS, SCSS and Stylus formats 15 | * PNG and WebP raster images in 8px, 16px, 24px, 32px, 48px and 64px. 16 | 17 | 18 | ## Getting Started 19 | 20 | #### For code samples and everything else you need to get started with Open Iconic, check out our [Icons](http://useiconic.com/open#icons) and [Reference](http://useiconic.com/open#reference) sections. 21 | 22 | ### General Usage 23 | 24 | #### Using Open Iconic's SVGs 25 | 26 | We like SVGs and we think they're the way to display icons on the web. Since Open Iconic are just basic SVGs, we suggest you display them like you would any other image (don't forget the `alt` attribute). 27 | 28 | ``` 29 | icon name 30 | ``` 31 | 32 | #### Using Open Iconic's SVG Sprite 33 | 34 | Open Iconic also comes in a SVG sprite which allows you to display all the icons in the set with a single request. It's like an icon font, without being a hack. 35 | 36 | Adding an icon from an SVG sprite is a little different than what you're used to, but it's still a piece of cake. *Tip: To make your icons easily style able, we suggest adding a general class to the* `` *tag and a unique class name for each different icon in the* `` *tag.* 37 | 38 | ``` 39 | 40 | 41 | 42 | ``` 43 | 44 | Sizing icons only needs basic CSS. All the icons are in a square format, so just set the `` tag with equal width and height dimensions. 45 | 46 | ``` 47 | .icon { 48 | width: 16px; 49 | height: 16px; 50 | } 51 | ``` 52 | 53 | Coloring icons is even easier. All you need to do is set the `fill` rule on the `` tag. 54 | 55 | ``` 56 | .icon-account-login { 57 | fill: #f00; 58 | } 59 | ``` 60 | 61 | To learn more about SVG Sprites, read [Chris Coyier's guide](http://css-tricks.com/svg-sprites-use-better-icon-fonts/). 62 | 63 | #### Using Open Iconic's Icon Font... 64 | 65 | 66 | ##### …with Bootstrap 67 | 68 | You can find our Bootstrap stylesheets in `font/css/open-iconic-bootstrap.{css, less, scss, styl}` 69 | 70 | 71 | ``` 72 | 73 | ``` 74 | 75 | 76 | ``` 77 | 78 | ``` 79 | 80 | ##### …with Foundation 81 | 82 | You can find our Foundation stylesheets in `font/css/open-iconic-foundation.{css, less, scss, styl}` 83 | 84 | ``` 85 | 86 | ``` 87 | 88 | 89 | ``` 90 | 91 | ``` 92 | 93 | ##### …on its own 94 | 95 | You can find our default stylesheets in `font/css/open-iconic.{css, less, scss, styl}` 96 | 97 | ``` 98 | 99 | ``` 100 | 101 | ``` 102 | 103 | ``` 104 | 105 | 106 | ## License 107 | 108 | ### Icons 109 | 110 | All code (including SVG markup) is under the [MIT License](http://opensource.org/licenses/MIT). 111 | 112 | ### Fonts 113 | 114 | All fonts are under the [SIL Licensed](http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web). 115 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/wwwroot/css/open-iconic/font/css/open-iconic-bootstrap.min.css: -------------------------------------------------------------------------------- 1 | @font-face{font-family:Icons;src:url(../fonts/open-iconic.eot);src:url(../fonts/open-iconic.eot?#iconic-sm) format('embedded-opentype'),url(../fonts/open-iconic.woff) format('woff'),url(../fonts/open-iconic.ttf) format('truetype'),url(../fonts/open-iconic.otf) format('opentype'),url(../fonts/open-iconic.svg#iconic-sm) format('svg');font-weight:400;font-style:normal}.oi{position:relative;top:1px;display:inline-block;speak:none;font-family:Icons;font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.oi:empty:before{width:1em;text-align:center;box-sizing:content-box}.oi.oi-align-center:before{text-align:center}.oi.oi-align-left:before{text-align:left}.oi.oi-align-right:before{text-align:right}.oi.oi-flip-horizontal:before{-webkit-transform:scale(-1,1);-ms-transform:scale(-1,1);transform:scale(-1,1)}.oi.oi-flip-vertical:before{-webkit-transform:scale(1,-1);-ms-transform:scale(-1,1);transform:scale(1,-1)}.oi.oi-flip-horizontal-vertical:before{-webkit-transform:scale(-1,-1);-ms-transform:scale(-1,1);transform:scale(-1,-1)}.oi-account-login:before{content:'\e000'}.oi-account-logout:before{content:'\e001'}.oi-action-redo:before{content:'\e002'}.oi-action-undo:before{content:'\e003'}.oi-align-center:before{content:'\e004'}.oi-align-left:before{content:'\e005'}.oi-align-right:before{content:'\e006'}.oi-aperture:before{content:'\e007'}.oi-arrow-bottom:before{content:'\e008'}.oi-arrow-circle-bottom:before{content:'\e009'}.oi-arrow-circle-left:before{content:'\e00a'}.oi-arrow-circle-right:before{content:'\e00b'}.oi-arrow-circle-top:before{content:'\e00c'}.oi-arrow-left:before{content:'\e00d'}.oi-arrow-right:before{content:'\e00e'}.oi-arrow-thick-bottom:before{content:'\e00f'}.oi-arrow-thick-left:before{content:'\e010'}.oi-arrow-thick-right:before{content:'\e011'}.oi-arrow-thick-top:before{content:'\e012'}.oi-arrow-top:before{content:'\e013'}.oi-audio-spectrum:before{content:'\e014'}.oi-audio:before{content:'\e015'}.oi-badge:before{content:'\e016'}.oi-ban:before{content:'\e017'}.oi-bar-chart:before{content:'\e018'}.oi-basket:before{content:'\e019'}.oi-battery-empty:before{content:'\e01a'}.oi-battery-full:before{content:'\e01b'}.oi-beaker:before{content:'\e01c'}.oi-bell:before{content:'\e01d'}.oi-bluetooth:before{content:'\e01e'}.oi-bold:before{content:'\e01f'}.oi-bolt:before{content:'\e020'}.oi-book:before{content:'\e021'}.oi-bookmark:before{content:'\e022'}.oi-box:before{content:'\e023'}.oi-briefcase:before{content:'\e024'}.oi-british-pound:before{content:'\e025'}.oi-browser:before{content:'\e026'}.oi-brush:before{content:'\e027'}.oi-bug:before{content:'\e028'}.oi-bullhorn:before{content:'\e029'}.oi-calculator:before{content:'\e02a'}.oi-calendar:before{content:'\e02b'}.oi-camera-slr:before{content:'\e02c'}.oi-caret-bottom:before{content:'\e02d'}.oi-caret-left:before{content:'\e02e'}.oi-caret-right:before{content:'\e02f'}.oi-caret-top:before{content:'\e030'}.oi-cart:before{content:'\e031'}.oi-chat:before{content:'\e032'}.oi-check:before{content:'\e033'}.oi-chevron-bottom:before{content:'\e034'}.oi-chevron-left:before{content:'\e035'}.oi-chevron-right:before{content:'\e036'}.oi-chevron-top:before{content:'\e037'}.oi-circle-check:before{content:'\e038'}.oi-circle-x:before{content:'\e039'}.oi-clipboard:before{content:'\e03a'}.oi-clock:before{content:'\e03b'}.oi-cloud-download:before{content:'\e03c'}.oi-cloud-upload:before{content:'\e03d'}.oi-cloud:before{content:'\e03e'}.oi-cloudy:before{content:'\e03f'}.oi-code:before{content:'\e040'}.oi-cog:before{content:'\e041'}.oi-collapse-down:before{content:'\e042'}.oi-collapse-left:before{content:'\e043'}.oi-collapse-right:before{content:'\e044'}.oi-collapse-up:before{content:'\e045'}.oi-command:before{content:'\e046'}.oi-comment-square:before{content:'\e047'}.oi-compass:before{content:'\e048'}.oi-contrast:before{content:'\e049'}.oi-copywriting:before{content:'\e04a'}.oi-credit-card:before{content:'\e04b'}.oi-crop:before{content:'\e04c'}.oi-dashboard:before{content:'\e04d'}.oi-data-transfer-download:before{content:'\e04e'}.oi-data-transfer-upload:before{content:'\e04f'}.oi-delete:before{content:'\e050'}.oi-dial:before{content:'\e051'}.oi-document:before{content:'\e052'}.oi-dollar:before{content:'\e053'}.oi-double-quote-sans-left:before{content:'\e054'}.oi-double-quote-sans-right:before{content:'\e055'}.oi-double-quote-serif-left:before{content:'\e056'}.oi-double-quote-serif-right:before{content:'\e057'}.oi-droplet:before{content:'\e058'}.oi-eject:before{content:'\e059'}.oi-elevator:before{content:'\e05a'}.oi-ellipses:before{content:'\e05b'}.oi-envelope-closed:before{content:'\e05c'}.oi-envelope-open:before{content:'\e05d'}.oi-euro:before{content:'\e05e'}.oi-excerpt:before{content:'\e05f'}.oi-expand-down:before{content:'\e060'}.oi-expand-left:before{content:'\e061'}.oi-expand-right:before{content:'\e062'}.oi-expand-up:before{content:'\e063'}.oi-external-link:before{content:'\e064'}.oi-eye:before{content:'\e065'}.oi-eyedropper:before{content:'\e066'}.oi-file:before{content:'\e067'}.oi-fire:before{content:'\e068'}.oi-flag:before{content:'\e069'}.oi-flash:before{content:'\e06a'}.oi-folder:before{content:'\e06b'}.oi-fork:before{content:'\e06c'}.oi-fullscreen-enter:before{content:'\e06d'}.oi-fullscreen-exit:before{content:'\e06e'}.oi-globe:before{content:'\e06f'}.oi-graph:before{content:'\e070'}.oi-grid-four-up:before{content:'\e071'}.oi-grid-three-up:before{content:'\e072'}.oi-grid-two-up:before{content:'\e073'}.oi-hard-drive:before{content:'\e074'}.oi-header:before{content:'\e075'}.oi-headphones:before{content:'\e076'}.oi-heart:before{content:'\e077'}.oi-home:before{content:'\e078'}.oi-image:before{content:'\e079'}.oi-inbox:before{content:'\e07a'}.oi-infinity:before{content:'\e07b'}.oi-info:before{content:'\e07c'}.oi-italic:before{content:'\e07d'}.oi-justify-center:before{content:'\e07e'}.oi-justify-left:before{content:'\e07f'}.oi-justify-right:before{content:'\e080'}.oi-key:before{content:'\e081'}.oi-laptop:before{content:'\e082'}.oi-layers:before{content:'\e083'}.oi-lightbulb:before{content:'\e084'}.oi-link-broken:before{content:'\e085'}.oi-link-intact:before{content:'\e086'}.oi-list-rich:before{content:'\e087'}.oi-list:before{content:'\e088'}.oi-location:before{content:'\e089'}.oi-lock-locked:before{content:'\e08a'}.oi-lock-unlocked:before{content:'\e08b'}.oi-loop-circular:before{content:'\e08c'}.oi-loop-square:before{content:'\e08d'}.oi-loop:before{content:'\e08e'}.oi-magnifying-glass:before{content:'\e08f'}.oi-map-marker:before{content:'\e090'}.oi-map:before{content:'\e091'}.oi-media-pause:before{content:'\e092'}.oi-media-play:before{content:'\e093'}.oi-media-record:before{content:'\e094'}.oi-media-skip-backward:before{content:'\e095'}.oi-media-skip-forward:before{content:'\e096'}.oi-media-step-backward:before{content:'\e097'}.oi-media-step-forward:before{content:'\e098'}.oi-media-stop:before{content:'\e099'}.oi-medical-cross:before{content:'\e09a'}.oi-menu:before{content:'\e09b'}.oi-microphone:before{content:'\e09c'}.oi-minus:before{content:'\e09d'}.oi-monitor:before{content:'\e09e'}.oi-moon:before{content:'\e09f'}.oi-move:before{content:'\e0a0'}.oi-musical-note:before{content:'\e0a1'}.oi-paperclip:before{content:'\e0a2'}.oi-pencil:before{content:'\e0a3'}.oi-people:before{content:'\e0a4'}.oi-person:before{content:'\e0a5'}.oi-phone:before{content:'\e0a6'}.oi-pie-chart:before{content:'\e0a7'}.oi-pin:before{content:'\e0a8'}.oi-play-circle:before{content:'\e0a9'}.oi-plus:before{content:'\e0aa'}.oi-power-standby:before{content:'\e0ab'}.oi-print:before{content:'\e0ac'}.oi-project:before{content:'\e0ad'}.oi-pulse:before{content:'\e0ae'}.oi-puzzle-piece:before{content:'\e0af'}.oi-question-mark:before{content:'\e0b0'}.oi-rain:before{content:'\e0b1'}.oi-random:before{content:'\e0b2'}.oi-reload:before{content:'\e0b3'}.oi-resize-both:before{content:'\e0b4'}.oi-resize-height:before{content:'\e0b5'}.oi-resize-width:before{content:'\e0b6'}.oi-rss-alt:before{content:'\e0b7'}.oi-rss:before{content:'\e0b8'}.oi-script:before{content:'\e0b9'}.oi-share-boxed:before{content:'\e0ba'}.oi-share:before{content:'\e0bb'}.oi-shield:before{content:'\e0bc'}.oi-signal:before{content:'\e0bd'}.oi-signpost:before{content:'\e0be'}.oi-sort-ascending:before{content:'\e0bf'}.oi-sort-descending:before{content:'\e0c0'}.oi-spreadsheet:before{content:'\e0c1'}.oi-star:before{content:'\e0c2'}.oi-sun:before{content:'\e0c3'}.oi-tablet:before{content:'\e0c4'}.oi-tag:before{content:'\e0c5'}.oi-tags:before{content:'\e0c6'}.oi-target:before{content:'\e0c7'}.oi-task:before{content:'\e0c8'}.oi-terminal:before{content:'\e0c9'}.oi-text:before{content:'\e0ca'}.oi-thumb-down:before{content:'\e0cb'}.oi-thumb-up:before{content:'\e0cc'}.oi-timer:before{content:'\e0cd'}.oi-transfer:before{content:'\e0ce'}.oi-trash:before{content:'\e0cf'}.oi-underline:before{content:'\e0d0'}.oi-vertical-align-bottom:before{content:'\e0d1'}.oi-vertical-align-center:before{content:'\e0d2'}.oi-vertical-align-top:before{content:'\e0d3'}.oi-video:before{content:'\e0d4'}.oi-volume-high:before{content:'\e0d5'}.oi-volume-low:before{content:'\e0d6'}.oi-volume-off:before{content:'\e0d7'}.oi-warning:before{content:'\e0d8'}.oi-wifi:before{content:'\e0d9'}.oi-wrench:before{content:'\e0da'}.oi-x:before{content:'\e0db'}.oi-yen:before{content:'\e0dc'}.oi-zoom-in:before{content:'\e0dd'}.oi-zoom-out:before{content:'\e0de'} -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/wwwroot/css/open-iconic/font/fonts/open-iconic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codemillmatt/dotnetconfpizza/ce67bca5205fab00b822a733c22d2e3e331e3880/PizzaConf/PizzaConf.Web/wwwroot/css/open-iconic/font/fonts/open-iconic.eot -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/wwwroot/css/open-iconic/font/fonts/open-iconic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codemillmatt/dotnetconfpizza/ce67bca5205fab00b822a733c22d2e3e331e3880/PizzaConf/PizzaConf.Web/wwwroot/css/open-iconic/font/fonts/open-iconic.otf -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codemillmatt/dotnetconfpizza/ce67bca5205fab00b822a733c22d2e3e331e3880/PizzaConf/PizzaConf.Web/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/wwwroot/css/open-iconic/font/fonts/open-iconic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codemillmatt/dotnetconfpizza/ce67bca5205fab00b822a733c22d2e3e331e3880/PizzaConf/PizzaConf.Web/wwwroot/css/open-iconic/font/fonts/open-iconic.woff -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | @import url('open-iconic/font/css/open-iconic-bootstrap.min.css'); 2 | 3 | html, body { 4 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 5 | } 6 | 7 | h1:focus { 8 | outline: none; 9 | } 10 | 11 | a, .btn-link { 12 | color: #0071c1; 13 | } 14 | 15 | .btn-primary { 16 | color: #fff; 17 | background-color: #1b6ec2; 18 | border-color: #1861ac; 19 | } 20 | 21 | .btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus { 22 | box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb; 23 | } 24 | 25 | .content { 26 | padding-top: 1.1rem; 27 | } 28 | 29 | .valid.modified:not([type=checkbox]) { 30 | outline: 1px solid #26b050; 31 | } 32 | 33 | .invalid { 34 | outline: 1px solid red; 35 | } 36 | 37 | .validation-message { 38 | color: red; 39 | } 40 | 41 | #blazor-error-ui { 42 | background: lightyellow; 43 | bottom: 0; 44 | box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); 45 | display: none; 46 | left: 0; 47 | padding: 0.6rem 1.25rem 0.7rem 1.25rem; 48 | position: fixed; 49 | width: 100%; 50 | z-index: 1000; 51 | } 52 | 53 | #blazor-error-ui .dismiss { 54 | cursor: pointer; 55 | position: absolute; 56 | right: 0.75rem; 57 | top: 0.5rem; 58 | } 59 | 60 | .blazor-error-boundary { 61 | background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121; 62 | padding: 1rem 1rem 1rem 3.7rem; 63 | color: white; 64 | } 65 | 66 | .blazor-error-boundary::after { 67 | content: "An error has occurred." 68 | } 69 | -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.Web/wwwroot/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codemillmatt/dotnetconfpizza/ce67bca5205fab00b822a733c22d2e3e331e3880/PizzaConf/PizzaConf.Web/wwwroot/favicon.png -------------------------------------------------------------------------------- /PizzaConf/PizzaConf.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.4.33015.44 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PizzaConf.Menu.Api", "PizzaConf.Menu.Api\PizzaConf.Menu.Api.csproj", "{1F251B14-8D5F-484F-89D5-07CFF5DC84D7}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PizzaConf.Models", "PizzaConf.Models\PizzaConf.Models.csproj", "{D6CD8F14-5B36-479A-A44F-9AFE71BE2EB0}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PizzaConf.Checkout.Api", "PizzaConf.Checkout.Api\PizzaConf.Checkout.Api.csproj", "{9A74FFB4-3F2A-45B6-9261-A27E4D5AAEF7}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PizzaConf.Web", "PizzaConf.Web\PizzaConf.Web.csproj", "{640ED021-C955-4CBE-B95F-001081B13184}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PizzaConf.DeliveryTracker", "PizzaConf.DeliveryTracker\PizzaConf.DeliveryTracker.csproj", "{E22D2F85-B3F0-44FA-B69A-44E1967823AE}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Release|Any CPU = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {1F251B14-8D5F-484F-89D5-07CFF5DC84D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {1F251B14-8D5F-484F-89D5-07CFF5DC84D7}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {1F251B14-8D5F-484F-89D5-07CFF5DC84D7}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {1F251B14-8D5F-484F-89D5-07CFF5DC84D7}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {D6CD8F14-5B36-479A-A44F-9AFE71BE2EB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {D6CD8F14-5B36-479A-A44F-9AFE71BE2EB0}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {D6CD8F14-5B36-479A-A44F-9AFE71BE2EB0}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {D6CD8F14-5B36-479A-A44F-9AFE71BE2EB0}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {9A74FFB4-3F2A-45B6-9261-A27E4D5AAEF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {9A74FFB4-3F2A-45B6-9261-A27E4D5AAEF7}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {9A74FFB4-3F2A-45B6-9261-A27E4D5AAEF7}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {9A74FFB4-3F2A-45B6-9261-A27E4D5AAEF7}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {640ED021-C955-4CBE-B95F-001081B13184}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {640ED021-C955-4CBE-B95F-001081B13184}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {640ED021-C955-4CBE-B95F-001081B13184}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {640ED021-C955-4CBE-B95F-001081B13184}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {E22D2F85-B3F0-44FA-B69A-44E1967823AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {E22D2F85-B3F0-44FA-B69A-44E1967823AE}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {E22D2F85-B3F0-44FA-B69A-44E1967823AE}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {E22D2F85-B3F0-44FA-B69A-44E1967823AE}.Release|Any CPU.Build.0 = Release|Any CPU 42 | EndGlobalSection 43 | GlobalSection(SolutionProperties) = preSolution 44 | HideSolutionNode = FALSE 45 | EndGlobalSection 46 | GlobalSection(ExtensibilityGlobals) = postSolution 47 | SolutionGuid = {1F32E291-B055-4037-A2FF-D894B6FCF236} 48 | EndGlobalSection 49 | EndGlobal 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dotnetconfpizza 2 | Blazor Pizza App and Azure for .NET Conf 3 | 4 | -------------------------------------------------------------------------------- /azure.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json 2 | 3 | name: dotnetconfpizza 4 | metadata: 5 | template: dotnetconf-whirlwind@0.0.1-beta 6 | services: 7 | tracker: 8 | project: PizzaConf/PizzaConf.DeliveryTracker 9 | language: csharp 10 | host: function 11 | menu: 12 | project: PizzaConf/PizzaConf.Menu.Api 13 | dist: build 14 | language: csharp 15 | host: containerapp 16 | module: app/menu 17 | docker: 18 | path: ./Dockerfile 19 | context: ../ 20 | checkout: 21 | project: PizzaConf/PizzaConf.Checkout.Api 22 | dist: build 23 | language: csharp 24 | host: containerapp 25 | module: app/checkout 26 | docker: 27 | path: ./Dockerfile 28 | context: ../ 29 | web: 30 | project: PizzaConf/PizzaConf.Web 31 | dist: build 32 | language: csharp 33 | host: containerapp 34 | module: app/web 35 | docker: 36 | path: ./Dockerfile 37 | context: ../ -------------------------------------------------------------------------------- /infra/abbreviations.json: -------------------------------------------------------------------------------- 1 | { 2 | "analysisServicesServers": "as", 3 | "apiManagementService": "apim-", 4 | "appConfigurationConfigurationStores": "appcs-", 5 | "appManagedEnvironments": "cae-", 6 | "appContainerApps": "ca-", 7 | "authorizationPolicyDefinitions": "policy-", 8 | "automationAutomationAccounts": "aa-", 9 | "blueprintBlueprints": "bp-", 10 | "blueprintBlueprintsArtifacts": "bpa-", 11 | "cacheRedis": "redis-", 12 | "cdnProfiles": "cdnp-", 13 | "cdnProfilesEndpoints": "cdne-", 14 | "cognitiveServicesAccounts": "cog-", 15 | "cognitiveServicesFormRecognizer": "cog-fr-", 16 | "cognitiveServicesTextAnalytics": "cog-ta-", 17 | "computeAvailabilitySets": "avail-", 18 | "computeCloudServices": "cld-", 19 | "computeDiskEncryptionSets": "des", 20 | "computeDisks": "disk", 21 | "computeDisksOs": "osdisk", 22 | "computeGalleries": "gal", 23 | "computeSnapshots": "snap-", 24 | "computeVirtualMachines": "vm", 25 | "computeVirtualMachineScaleSets": "vmss-", 26 | "containerInstanceContainerGroups": "ci", 27 | "containerRegistryRegistries": "cr", 28 | "containerServiceManagedClusters": "aks-", 29 | "databricksWorkspaces": "dbw-", 30 | "dataFactoryFactories": "adf-", 31 | "dataLakeAnalyticsAccounts": "dla", 32 | "dataLakeStoreAccounts": "dls", 33 | "dataMigrationServices": "dms-", 34 | "dBforMySQLServers": "mysql-", 35 | "dBforPostgreSQLServers": "psql-", 36 | "devicesIotHubs": "iot-", 37 | "devicesProvisioningServices": "provs-", 38 | "devicesProvisioningServicesCertificates": "pcert-", 39 | "documentDBDatabaseAccounts": "cosmos-", 40 | "eventGridDomains": "evgd-", 41 | "eventGridDomainsTopics": "evgt-", 42 | "eventGridEventSubscriptions": "evgs-", 43 | "eventHubNamespaces": "evhns-", 44 | "eventHubNamespacesEventHubs": "evh-", 45 | "hdInsightClustersHadoop": "hadoop-", 46 | "hdInsightClustersHbase": "hbase-", 47 | "hdInsightClustersKafka": "kafka-", 48 | "hdInsightClustersMl": "mls-", 49 | "hdInsightClustersSpark": "spark-", 50 | "hdInsightClustersStorm": "storm-", 51 | "hybridComputeMachines": "arcs-", 52 | "insightsActionGroups": "ag-", 53 | "insightsComponents": "appi-", 54 | "keyVaultVaults": "kv-", 55 | "kubernetesConnectedClusters": "arck", 56 | "kustoClusters": "dec", 57 | "kustoClustersDatabases": "dedb", 58 | "logicIntegrationAccounts": "ia-", 59 | "logicWorkflows": "logic-", 60 | "machineLearningServicesWorkspaces": "mlw-", 61 | "managedIdentityUserAssignedIdentities": "id-", 62 | "managementManagementGroups": "mg-", 63 | "migrateAssessmentProjects": "migr-", 64 | "networkApplicationGateways": "agw-", 65 | "networkApplicationSecurityGroups": "asg-", 66 | "networkAzureFirewalls": "afw-", 67 | "networkBastionHosts": "bas-", 68 | "networkConnections": "con-", 69 | "networkDnsZones": "dnsz-", 70 | "networkExpressRouteCircuits": "erc-", 71 | "networkFirewallPolicies": "afwp-", 72 | "networkFirewallPoliciesWebApplication": "waf", 73 | "networkFirewallPoliciesRuleGroups": "wafrg", 74 | "networkFrontDoors": "fd-", 75 | "networkFrontdoorWebApplicationFirewallPolicies": "fdfp-", 76 | "networkLoadBalancersExternal": "lbe-", 77 | "networkLoadBalancersInternal": "lbi-", 78 | "networkLoadBalancersInboundNatRules": "rule-", 79 | "networkLocalNetworkGateways": "lgw-", 80 | "networkNatGateways": "ng-", 81 | "networkNetworkInterfaces": "nic-", 82 | "networkNetworkSecurityGroups": "nsg-", 83 | "networkNetworkSecurityGroupsSecurityRules": "nsgsr-", 84 | "networkNetworkWatchers": "nw-", 85 | "networkPrivateDnsZones": "pdnsz-", 86 | "networkPrivateLinkServices": "pl-", 87 | "networkPublicIPAddresses": "pip-", 88 | "networkPublicIPPrefixes": "ippre-", 89 | "networkRouteFilters": "rf-", 90 | "networkRouteTables": "rt-", 91 | "networkRouteTablesRoutes": "udr-", 92 | "networkTrafficManagerProfiles": "traf-", 93 | "networkVirtualNetworkGateways": "vgw-", 94 | "networkVirtualNetworks": "vnet-", 95 | "networkVirtualNetworksSubnets": "snet-", 96 | "networkVirtualNetworksVirtualNetworkPeerings": "peer-", 97 | "networkVirtualWans": "vwan-", 98 | "networkVpnGateways": "vpng-", 99 | "networkVpnGatewaysVpnConnections": "vcn-", 100 | "networkVpnGatewaysVpnSites": "vst-", 101 | "notificationHubsNamespaces": "ntfns-", 102 | "notificationHubsNamespacesNotificationHubs": "ntf-", 103 | "operationalInsightsWorkspaces": "log-", 104 | "portalDashboards": "dash-", 105 | "powerBIDedicatedCapacities": "pbi-", 106 | "purviewAccounts": "pview-", 107 | "recoveryServicesVaults": "rsv-", 108 | "resourcesResourceGroups": "rg-", 109 | "searchSearchServices": "srch-", 110 | "serviceBusNamespaces": "sb-", 111 | "serviceBusNamespacesQueues": "sbq-", 112 | "serviceBusNamespacesTopics": "sbt-", 113 | "serviceEndPointPolicies": "se-", 114 | "serviceFabricClusters": "sf-", 115 | "signalRServiceSignalR": "sigr", 116 | "sqlManagedInstances": "sqlmi-", 117 | "sqlServers": "sql-", 118 | "sqlServersDataWarehouse": "sqldw-", 119 | "sqlServersDatabases": "sqldb-", 120 | "sqlServersDatabasesStretch": "sqlstrdb-", 121 | "storageStorageAccounts": "st", 122 | "storageStorageAccountsVm": "stvm", 123 | "storSimpleManagers": "ssimp", 124 | "streamAnalyticsCluster": "asa-", 125 | "synapseWorkspaces": "syn", 126 | "synapseWorkspacesAnalyticsWorkspaces": "synw", 127 | "synapseWorkspacesSqlPoolsDedicated": "syndp", 128 | "synapseWorkspacesSqlPoolsSpark": "synsp", 129 | "timeSeriesInsightsEnvironments": "tsi-", 130 | "webServerFarms": "plan-", 131 | "webSitesAppService": "app-", 132 | "webSitesAppServiceEnvironment": "ase-", 133 | "webSitesFunctions": "func-", 134 | "webStaticSites": "stapp-" 135 | } -------------------------------------------------------------------------------- /infra/app/checkout.bicep: -------------------------------------------------------------------------------- 1 | param location string = resourceGroup().location 2 | param tags object = {} 3 | param environmentName string 4 | param caeName string 5 | param appConfigName string 6 | param keyVaultName string 7 | param containerRegistryName string 8 | param imageName string 9 | 10 | var serviceName = 'checkout' 11 | 12 | resource containerAppEnvironment 'Microsoft.App/managedEnvironments@2022-06-01-preview' existing = { 13 | name: caeName 14 | } 15 | 16 | resource appConfig 'Microsoft.AppConfiguration/configurationStores@2022-05-01' existing = { 17 | name: appConfigName 18 | } 19 | 20 | resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { 21 | name: keyVaultName 22 | } 23 | 24 | resource containerRegistry 'Microsoft.ContainerRegistry/registries@2022-02-01-preview' existing = { 25 | name: containerRegistryName 26 | } 27 | 28 | resource checkoutApi 'Microsoft.App/containerApps@2022-06-01-preview' = { 29 | name: '${environmentName}${serviceName}' 30 | location: location 31 | tags: union(tags, { 'azd-service-name': serviceName }) 32 | identity: { type: 'SystemAssigned' } 33 | properties: { 34 | managedEnvironmentId: containerAppEnvironment.id 35 | configuration: { 36 | ingress: { 37 | external: true 38 | targetPort: 80 39 | allowInsecure: false 40 | transport: 'auto' 41 | } 42 | activeRevisionsMode: 'Single' 43 | dapr: { 44 | enabled: true 45 | appId: 'checkoutapi' 46 | } 47 | secrets: [ 48 | { 49 | name: 'registry-password' 50 | value: containerRegistry.listCredentials().passwords[0].value 51 | } 52 | ] 53 | registries: [ 54 | { 55 | server: '${containerRegistry.name}.azurecr.io' 56 | username: containerRegistry.name 57 | passwordSecretRef: 'registry-password' 58 | } 59 | ] 60 | } 61 | template: { 62 | containers: [ 63 | { 64 | image: !empty(imageName) ? imageName : 'nginx:latest' 65 | name: 'pizzaconfcheckoutapi' 66 | env: [ 67 | { 68 | name: 'ASPNETCORE_ENVIRONMENT' 69 | value: 'Development' 70 | } 71 | { 72 | name: 'appConfigUrl' 73 | value: appConfig.properties.endpoint 74 | } 75 | ] 76 | } 77 | ] 78 | } 79 | } 80 | } 81 | 82 | resource keyVaultAccessPolicies 'Microsoft.KeyVault/vaults/accessPolicies@2022-07-01' = { 83 | name: 'add' 84 | parent: keyVault 85 | properties: { 86 | accessPolicies: [ 87 | { 88 | objectId: checkoutApi.identity.principalId 89 | permissions: { 90 | secrets: [ 91 | 'get' 92 | 'list' 93 | ] 94 | } 95 | tenantId: subscription().tenantId 96 | } 97 | ] 98 | } 99 | } 100 | 101 | resource appConfigReader 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { 102 | name: '516239f1-63e1-4d78-a4de-a74fb236a071' 103 | scope: subscription() 104 | } 105 | 106 | resource appConfigAccessPolicies 'Microsoft.Authorization/roleAssignments@2022-04-01' = { 107 | name: guid(checkoutApi.name, appConfig.name) 108 | scope: appConfig 109 | properties: { 110 | roleDefinitionId: appConfigReader.id 111 | principalId: checkoutApi.identity.principalId 112 | principalType: 'ServicePrincipal' 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /infra/app/checkout.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "environmentName": { 6 | "value": "${AZURE_ENV_NAME}" 7 | }, 8 | "location": { 9 | "value": "${AZURE_LOCATION}" 10 | }, 11 | "imageName": { 12 | "value": "${SERVICE_CHECKOUT_IMAGE_NAME}" 13 | }, 14 | "caeName": { 15 | "value": "${AZURE_CONTAINER_APPS_ENVIRONMENT_NAME}" 16 | }, 17 | "appConfigName": { 18 | "value": "${AZURE_APP_CONFIG_NAME}" 19 | }, 20 | "keyVaultName": { 21 | "value": "${AZURE_KEYVAULT_NAME}" 22 | }, 23 | "containerRegistryName": { 24 | "value": "${AZURE_CONTAINER_REGISTRY_NAME}" 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /infra/app/menu.bicep: -------------------------------------------------------------------------------- 1 | param location string = resourceGroup().location 2 | param environmentName string 3 | param tags object = {} 4 | 5 | param caeName string 6 | param appConfigName string 7 | param keyVaultName string 8 | param containerRegistryName string 9 | param imageName string 10 | param azureStorageAccountName string 11 | 12 | var serviceName = 'menu' 13 | 14 | resource containerAppEnvironment 'Microsoft.App/managedEnvironments@2022-06-01-preview' existing = { 15 | name: caeName 16 | } 17 | 18 | resource appConfig 'Microsoft.AppConfiguration/configurationStores@2022-05-01' existing = { 19 | name: appConfigName 20 | } 21 | 22 | resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { 23 | name: keyVaultName 24 | } 25 | 26 | resource containerRegistry 'Microsoft.ContainerRegistry/registries@2022-02-01-preview' existing = { 27 | name: containerRegistryName 28 | } 29 | 30 | resource storageAccount 'Microsoft.Storage/storageAccounts@2022-05-01' existing = { 31 | name: azureStorageAccountName 32 | } 33 | 34 | resource menuApi 'Microsoft.App/containerApps@2022-06-01-preview' = { 35 | name: '${environmentName}${serviceName}' 36 | location: location 37 | tags: union(tags, { 'azd-service-name': serviceName }) 38 | identity: { type: 'SystemAssigned' } 39 | properties: { 40 | managedEnvironmentId: containerAppEnvironment.id 41 | configuration: { 42 | ingress: { 43 | external: true 44 | targetPort: 80 45 | allowInsecure: false 46 | transport: 'auto' 47 | } 48 | activeRevisionsMode: 'Single' 49 | dapr: { 50 | enabled: true 51 | appId: 'menuapi' 52 | } 53 | secrets: [ 54 | { 55 | name: 'registry-password' 56 | value: containerRegistry.listCredentials().passwords[0].value 57 | } 58 | ] 59 | registries: [ 60 | { 61 | server: '${containerRegistry.name}.azurecr.io' 62 | username: containerRegistry.name 63 | passwordSecretRef: 'registry-password' 64 | } 65 | ] 66 | } 67 | template: { 68 | containers: [ 69 | { 70 | image: !empty(imageName) ? imageName : 'nginx:latest' 71 | name: 'pizzaconfmenuapi' 72 | env: [ 73 | { 74 | name: 'ASPNETCORE_ENVIRONMENT' 75 | value: 'Development' 76 | } 77 | { 78 | name: 'appConfigUrl' 79 | value: appConfig.properties.endpoint 80 | } 81 | ] 82 | } 83 | ] 84 | } 85 | } 86 | } 87 | 88 | resource keyVaultAccessPolicies 'Microsoft.KeyVault/vaults/accessPolicies@2022-07-01' = { 89 | name: 'add' 90 | parent: keyVault 91 | properties: { 92 | accessPolicies: [ 93 | { 94 | objectId: menuApi.identity.principalId 95 | permissions: { 96 | secrets: [ 97 | 'get' 98 | 'list' 99 | ] 100 | } 101 | tenantId: subscription().tenantId 102 | } 103 | ] 104 | } 105 | } 106 | 107 | resource appConfigReader 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { 108 | name: '516239f1-63e1-4d78-a4de-a74fb236a071' 109 | scope: subscription() 110 | } 111 | 112 | resource appConfigAccessPolicies 'Microsoft.Authorization/roleAssignments@2022-04-01' = { 113 | name: guid(menuApi.name, appConfig.name) 114 | scope: appConfig 115 | properties: { 116 | roleDefinitionId: appConfigReader.id 117 | principalId: menuApi.identity.principalId 118 | principalType: 'ServicePrincipal' 119 | } 120 | } 121 | 122 | resource storageBlobDataContributor 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { 123 | name: 'ba92f5b4-2d11-453d-a403-e96b0029c9fe' 124 | scope: subscription() 125 | } 126 | 127 | resource storageAccountAccessPolicies 'Microsoft.Authorization/roleAssignments@2022-04-01' = { 128 | name: guid(menuApi.name, storageAccount.name) 129 | scope: storageAccount 130 | properties: { 131 | roleDefinitionId: storageBlobDataContributor.id 132 | principalId: menuApi.identity.principalId 133 | principalType: 'ServicePrincipal' 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /infra/app/menu.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "environmentName": { 6 | "value": "${AZURE_ENV_NAME}" 7 | }, 8 | "location": { 9 | "value": "${AZURE_LOCATION}" 10 | }, 11 | "imageName": { 12 | "value": "${SERVICE_MENU_IMAGE_NAME}" 13 | }, 14 | "caeName": { 15 | "value": "${AZURE_CONTAINER_APPS_ENVIRONMENT_NAME}" 16 | }, 17 | "appConfigName": { 18 | "value": "${AZURE_APP_CONFIG_NAME}" 19 | }, 20 | "keyVaultName": { 21 | "value": "${AZURE_KEYVAULT_NAME}" 22 | }, 23 | "containerRegistryName": { 24 | "value": "${AZURE_CONTAINER_REGISTRY_NAME}" 25 | }, 26 | "azureStorageAccountName": { 27 | "value": "${AZURE_STORAGE_ACCOUNT_NAME}" 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /infra/app/web.bicep: -------------------------------------------------------------------------------- 1 | param location string = resourceGroup().location 2 | param environmentName string 3 | param tags object = {} 4 | 5 | param caeName string 6 | param appConfigName string 7 | param keyVaultName string 8 | param containerRegistryName string 9 | param imageName string 10 | 11 | var serviceName = 'web' 12 | 13 | resource containerAppEnvironment 'Microsoft.App/managedEnvironments@2022-06-01-preview' existing = { 14 | name: caeName 15 | } 16 | 17 | resource appConfig 'Microsoft.AppConfiguration/configurationStores@2022-05-01' existing = { 18 | name: appConfigName 19 | } 20 | 21 | resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { 22 | name: keyVaultName 23 | } 24 | 25 | resource containerRegistry 'Microsoft.ContainerRegistry/registries@2022-02-01-preview' existing = { 26 | name: containerRegistryName 27 | } 28 | 29 | resource web 'Microsoft.App/containerApps@2022-06-01-preview' = { 30 | name: '${environmentName}${serviceName}' 31 | location: location 32 | tags: union(tags, { 'azd-service-name': serviceName }) 33 | identity: { type: 'SystemAssigned' } 34 | properties: { 35 | managedEnvironmentId: containerAppEnvironment.id 36 | configuration: { 37 | ingress: { 38 | external: true 39 | targetPort: 80 40 | allowInsecure: false 41 | transport: 'auto' 42 | } 43 | activeRevisionsMode: 'Single' 44 | dapr: { 45 | enabled: true 46 | appId: 'web' 47 | } 48 | secrets: [ 49 | { 50 | name: 'registry-password' 51 | value: containerRegistry.listCredentials().passwords[0].value 52 | } 53 | ] 54 | registries: [ 55 | { 56 | server: '${containerRegistry.name}.azurecr.io' 57 | username: containerRegistry.name 58 | passwordSecretRef: 'registry-password' 59 | } 60 | ] 61 | } 62 | template: { 63 | containers: [ 64 | { 65 | image: !empty(imageName) ? imageName : 'nginx:latest' 66 | name: 'pizzaconfweb' 67 | env: [ 68 | { 69 | name: 'ASPNETCORE_ENVIRONMENT' 70 | value: 'Development' 71 | } 72 | { 73 | name: 'appConfigUrl' 74 | value: appConfig.properties.endpoint 75 | } 76 | ] 77 | } 78 | ] 79 | } 80 | } 81 | } 82 | 83 | resource keyVaultAccessPolicies 'Microsoft.KeyVault/vaults/accessPolicies@2022-07-01' = { 84 | name: 'add' 85 | parent: keyVault 86 | properties: { 87 | accessPolicies: [ 88 | { 89 | objectId: web.identity.principalId 90 | permissions: { 91 | secrets: [ 92 | 'get' 93 | 'list' 94 | ] 95 | } 96 | tenantId: subscription().tenantId 97 | } 98 | ] 99 | } 100 | } 101 | 102 | resource appConfigReader 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { 103 | name: '516239f1-63e1-4d78-a4de-a74fb236a071' 104 | scope: subscription() 105 | } 106 | 107 | resource appConfigAccessPolicies 'Microsoft.Authorization/roleAssignments@2022-04-01' = { 108 | name: guid(web.name, appConfig.name) 109 | scope: appConfig 110 | properties: { 111 | roleDefinitionId: appConfigReader.id 112 | principalId: web.identity.principalId 113 | principalType: 'ServicePrincipal' 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /infra/app/web.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "environmentName": { 6 | "value": "${AZURE_ENV_NAME}" 7 | }, 8 | "location": { 9 | "value": "${AZURE_LOCATION}" 10 | }, 11 | "imageName": { 12 | "value": "${SERVICE_WEB_IMAGE_NAME}" 13 | }, 14 | "caeName": { 15 | "value": "${AZURE_CONTAINER_APPS_ENVIRONMENT_NAME}" 16 | }, 17 | "appConfigName": { 18 | "value": "${AZURE_APP_CONFIG_NAME}" 19 | }, 20 | "keyVaultName": { 21 | "value": "${AZURE_KEYVAULT_NAME}" 22 | }, 23 | "containerRegistryName": { 24 | "value": "${AZURE_CONTAINER_REGISTRY_NAME}" 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /infra/core/app-config/azure-app-config.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | param tags object = {} 4 | 5 | param menuSecretUri string 6 | param checkoutSecretUri string 7 | param signalRSecretUri string 8 | 9 | param azureSignalRKeyName string 10 | param cartUrlKeyName string 11 | param checkoutDbKeyName string 12 | param daprCheckoutApiKeyName string 13 | param daprMenuApiKeyName string 14 | param menuDbKeyName string 15 | param menuUrlKeyName string 16 | 17 | param cartUrlValue string 18 | param daprCheckoutApiValue string 19 | param daprMenuApiValue string 20 | param menuUrlValue string 21 | 22 | param imageCdnHostUrlKeyName string 23 | param imageCdnHostUrlValue string 24 | 25 | param imageStorageUrlKeyName string 26 | param imageStorageUrlValue string 27 | 28 | resource appConfig 'Microsoft.AppConfiguration/configurationStores@2022-05-01' = { 29 | name: name 30 | location: location 31 | tags: tags 32 | sku: { 33 | name: 'Standard' 34 | } 35 | } 36 | 37 | resource signalRKeyVaultStore 'Microsoft.AppConfiguration/configurationStores/keyValues@2022-05-01' = { 38 | parent: appConfig 39 | name: azureSignalRKeyName 40 | properties: { 41 | value: string({ uri: signalRSecretUri }) 42 | contentType: 'application/vnd.microsoft.appconfig.keyvaultref+json;charset=utf-8' 43 | } 44 | } 45 | 46 | resource menuDbKeyVaultStore 'Microsoft.AppConfiguration/configurationStores/keyValues@2022-05-01' = { 47 | parent: appConfig 48 | name: checkoutDbKeyName 49 | properties: { 50 | value: string({ uri: menuSecretUri }) 51 | contentType: 'application/vnd.microsoft.appconfig.keyvaultref+json;charset=utf-8' 52 | } 53 | } 54 | 55 | resource checkoutDbKeyVaultStore 'Microsoft.AppConfiguration/configurationStores/keyValues@2022-05-01' = { 56 | parent: appConfig 57 | name: menuDbKeyName 58 | properties: { 59 | value: string({ uri: checkoutSecretUri }) 60 | contentType: 'application/vnd.microsoft.appconfig.keyvaultref+json;charset=utf-8' 61 | } 62 | } 63 | 64 | resource imageCdnUrlStore 'Microsoft.AppConfiguration/configurationStores/keyValues@2022-05-01' = { 65 | parent: appConfig 66 | name: imageCdnHostUrlKeyName 67 | properties: { 68 | value: imageCdnHostUrlValue 69 | } 70 | } 71 | 72 | resource cartUrlStore 'Microsoft.AppConfiguration/configurationStores/keyValues@2022-05-01' = { 73 | parent: appConfig 74 | name: cartUrlKeyName 75 | properties: { 76 | value: cartUrlValue 77 | } 78 | } 79 | 80 | resource daprCheckoutApiStore 'Microsoft.AppConfiguration/configurationStores/keyValues@2022-05-01' = { 81 | parent: appConfig 82 | name: daprCheckoutApiKeyName 83 | properties: { 84 | value: daprCheckoutApiValue 85 | } 86 | } 87 | 88 | resource daprMenuApiStore 'Microsoft.AppConfiguration/configurationStores/keyValues@2022-05-01' = { 89 | parent: appConfig 90 | name: daprMenuApiKeyName 91 | properties: { 92 | value: daprMenuApiValue 93 | } 94 | } 95 | 96 | resource menuUrlStore 'Microsoft.AppConfiguration/configurationStores/keyValues@2022-05-01' = { 97 | parent: appConfig 98 | name: menuUrlKeyName 99 | properties: { 100 | value: menuUrlValue 101 | } 102 | } 103 | 104 | resource imageStorageUrlStore 'Microsoft.AppConfiguration/configurationStores/keyValues@2022-05-01' = { 105 | parent: appConfig 106 | name: imageStorageUrlKeyName 107 | properties: { 108 | value: imageStorageUrlValue 109 | } 110 | } 111 | 112 | 113 | 114 | output appConfigName string = appConfig.name 115 | output appConfigUrl string = appConfig.properties.endpoint 116 | -------------------------------------------------------------------------------- /infra/core/cdn/endpoint.bicep: -------------------------------------------------------------------------------- 1 | param profileName string 2 | param endpointName string 3 | param location string = resourceGroup().location 4 | param tags object = {} 5 | 6 | param storageAccountHostName string 7 | 8 | resource cdnProfile 'Microsoft.Cdn/profiles@2021-06-01' = { 9 | name: profileName 10 | location: location 11 | tags: tags 12 | sku: { 13 | name: 'Standard_Verizon' 14 | } 15 | } 16 | 17 | resource endpoint 'Microsoft.Cdn/profiles/endpoints@2021-06-01' = { 18 | parent: cdnProfile 19 | name: endpointName 20 | location: location 21 | tags: tags 22 | properties: { 23 | originHostHeader: storageAccountHostName 24 | isHttpAllowed: true 25 | isHttpsAllowed: true 26 | queryStringCachingBehavior: 'IgnoreQueryString' 27 | contentTypesToCompress: [ 28 | 'text/plain' 29 | 'text/html' 30 | 'text/css' 31 | 'application/x-javascript' 32 | 'text/javascript' 33 | ] 34 | isCompressionEnabled: true 35 | origins: [ 36 | { 37 | name: 'origin1' 38 | properties: { 39 | hostName: storageAccountHostName 40 | } 41 | } 42 | ] 43 | } 44 | } 45 | 46 | output hostName string = endpoint.properties.hostName 47 | output originHostHeader string = endpoint.properties.originHostHeader 48 | -------------------------------------------------------------------------------- /infra/core/container-apps/container-apps.bicep: -------------------------------------------------------------------------------- 1 | param containerAppsEnvName string 2 | param containerRegistryName string 3 | param location string = resourceGroup().location 4 | param tags object = {} 5 | 6 | param logAnalyticsWorkspaceName string 7 | 8 | resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' existing = { 9 | name: logAnalyticsWorkspaceName 10 | } 11 | 12 | resource containerRegistry 'Microsoft.ContainerRegistry/registries@2022-02-01-preview' = { 13 | name: containerRegistryName 14 | location: location 15 | tags: tags 16 | sku: { 17 | name: 'Standard' 18 | } 19 | properties: { 20 | adminUserEnabled: true 21 | anonymousPullEnabled: false 22 | dataEndpointEnabled: false 23 | encryption: { 24 | status: 'Disabled' 25 | } 26 | networkRuleBypassOptions: 'AzureServices' 27 | publicNetworkAccess: 'Enabled' 28 | zoneRedundancy: 'Disabled' 29 | } 30 | } 31 | 32 | resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2022-06-01-preview' = { 33 | name: containerAppsEnvName 34 | location: location 35 | tags: tags 36 | properties: { 37 | appLogsConfiguration: { 38 | destination: 'log-analytics' 39 | logAnalyticsConfiguration: { 40 | customerId: logAnalyticsWorkspace.properties.customerId 41 | sharedKey: logAnalyticsWorkspace.listKeys().primarySharedKey 42 | } 43 | } 44 | } 45 | } 46 | 47 | output AZURE_CONTAINER_REGISTRY_NAME string = containerRegistry.name 48 | output AZURE_CONTAINER_REGISTRY_ENDPOINT string = containerRegistry.properties.loginServer 49 | output AZURE_CONTAINER_APPS_ENVIRONMENT_NAME string = containerAppsEnvironment.name 50 | -------------------------------------------------------------------------------- /infra/core/host/functions.bicep: -------------------------------------------------------------------------------- 1 | param functionAppServicePlanName string 2 | param functionAppName string 3 | param location string = resourceGroup().location 4 | param tags object = {} 5 | 6 | param appInsightsName string 7 | param storageAccountName string 8 | 9 | param trackingUrlKeyName string 10 | 11 | param appConfigName string 12 | param keyVaultName string 13 | 14 | var functionRuntime = 'dotnet' 15 | 16 | resource appConfig 'Microsoft.AppConfiguration/configurationStores@2022-05-01' existing = { 17 | name: appConfigName 18 | } 19 | 20 | resource keyVault 'Microsoft.KeyVault/vaults@2021-04-01-preview' existing = { 21 | name: keyVaultName 22 | } 23 | 24 | resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = { 25 | name: storageAccountName 26 | location: location 27 | kind: 'Storage' 28 | tags: tags 29 | sku: { 30 | name: 'Standard_LRS' 31 | } 32 | } 33 | 34 | resource appInsights 'Microsoft.Insights/components@2020-02-02' = { 35 | name: appInsightsName 36 | location: location 37 | tags: tags 38 | kind: 'web' 39 | properties: { 40 | Application_Type: 'web' 41 | publicNetworkAccessForIngestion: 'Enabled' 42 | publicNetworkAccessForQuery: 'Enabled' 43 | } 44 | } 45 | 46 | resource plan 'Microsoft.Web/serverfarms@2022-03-01' = { 47 | name: functionAppServicePlanName 48 | location: location 49 | tags: tags 50 | sku: { 51 | name: 'Y1' 52 | } 53 | properties: {} 54 | } 55 | 56 | resource functionApp 'Microsoft.Web/sites@2022-03-01' = { 57 | name: functionAppName 58 | location: location 59 | tags: union(tags, { 60 | 'azd-service-name': 'tracker' 61 | }) 62 | kind: 'functionapp' 63 | identity: { 64 | type: 'SystemAssigned' 65 | } 66 | properties: { 67 | serverFarmId: plan.id 68 | siteConfig: { 69 | appSettings: [ 70 | { 71 | name: 'AzureWebJobsStorage' 72 | value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storageAccount.id, storageAccount.apiVersion).keys[0].value}' 73 | } 74 | { 75 | name: 'FUNCTIONS_WORKER_RUNTIME' 76 | value: functionRuntime 77 | } 78 | { 79 | name: 'FUNCTIONS_EXTENSION_VERSION' 80 | value: '~4' 81 | } 82 | { 83 | name: 'APPINSIGHTS_INSTRUMENTATIONKEY' 84 | value: appInsights.properties.InstrumentationKey 85 | } 86 | { 87 | name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' 88 | value: 'InstrumentationKey=${appInsights.properties.InstrumentationKey}' 89 | } 90 | { 91 | name: 'ASPNETCORE_HOSTINGSTARTUPASSEMBLIES' 92 | value: 'Microsoft.Azure.SignalR' 93 | } 94 | { 95 | name: 'Azure__SignalR__StickyServerMode' 96 | value: 'Required' 97 | } 98 | { 99 | name: 'appConfigUrl' 100 | value: appConfig.properties.endpoint 101 | } 102 | { 103 | name: 'WEBSITE_RUN_FROM_PACKAGE' 104 | value: '1' 105 | } 106 | ] 107 | } 108 | httpsOnly: true 109 | } 110 | } 111 | 112 | // give the function app access to key vault 113 | resource functionAppKeyVaultAccessPolicy 'Microsoft.KeyVault/vaults/accessPolicies@2021-04-01-preview' = { 114 | name: 'add' 115 | parent: keyVault 116 | properties: { 117 | accessPolicies: [ 118 | { 119 | tenantId: keyVault.properties.tenantId 120 | objectId: functionApp.identity.principalId 121 | permissions: { 122 | secrets: [ 123 | 'get','list' 124 | ] 125 | } 126 | } 127 | ] 128 | } 129 | } 130 | 131 | // give the funciton app read access to app configuration 132 | resource functionAppAppConfigAccess 'Microsoft.Authorization/roleAssignments@2022-04-01' = { 133 | name: guid(functionApp.name, appConfig.name) 134 | scope: appConfig 135 | properties: { 136 | roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071') 137 | principalId: functionApp.identity.principalId 138 | principalType: 'ServicePrincipal' 139 | } 140 | } 141 | 142 | // add the function app's URL to app configuration 143 | resource trackingUrlStore 'Microsoft.AppConfiguration/configurationStores/keyValues@2022-05-01' = { 144 | parent: appConfig 145 | name: trackingUrlKeyName 146 | properties: { 147 | value: 'https://${functionApp.properties.defaultHostName}' 148 | } 149 | } 150 | 151 | output functionAppUrl string = functionApp.properties.defaultHostName 152 | -------------------------------------------------------------------------------- /infra/core/key-vault/key-vault.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | param tags object = {} 4 | param azurePrincipalId string 5 | 6 | resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { 7 | name: name 8 | location: location 9 | tags: tags 10 | properties: { 11 | enabledForDeployment: true 12 | sku: { 13 | name: 'standard' 14 | family: 'A' 15 | } 16 | tenantId: subscription().tenantId 17 | accessPolicies: [ 18 | { 19 | tenantId: subscription().tenantId 20 | objectId: azurePrincipalId 21 | permissions: { 22 | keys: [ 23 | 'all' 24 | ] 25 | secrets: [ 26 | 'all' 27 | ] 28 | certificates: [ 29 | 'all' 30 | ] 31 | } 32 | } 33 | ] 34 | } 35 | } 36 | 37 | output keyVaultName string = keyVault.name 38 | -------------------------------------------------------------------------------- /infra/core/log-analytics/log-analytics.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | param tags object = {} 4 | 5 | resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { 6 | name: name 7 | location: location 8 | tags: tags 9 | properties: { 10 | retentionInDays: 30 11 | sku: { 12 | name: 'PerGB2018' 13 | } 14 | } 15 | } 16 | 17 | output logAnalyticsWorkspaceName string = logAnalyticsWorkspace.name 18 | -------------------------------------------------------------------------------- /infra/core/monitor/applicationinsights.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param dashboardName string 3 | param location string = resourceGroup().location 4 | param tags object = {} 5 | 6 | param logAnalyticsWorkspaceId string 7 | 8 | resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = { 9 | name: name 10 | location: location 11 | tags: tags 12 | kind: 'web' 13 | properties: { 14 | Application_Type: 'web' 15 | WorkspaceResourceId: logAnalyticsWorkspaceId 16 | } 17 | } 18 | 19 | module applicationInsightsDashboard 'applicationinsights-dashboard.bicep' = { 20 | name: 'application-insights-dashboard' 21 | params: { 22 | name: dashboardName 23 | location: location 24 | applicationInsightsName: applicationInsights.name 25 | } 26 | } 27 | 28 | output connectionString string = applicationInsights.properties.ConnectionString 29 | output instrumentationKey string = applicationInsights.properties.InstrumentationKey 30 | output name string = applicationInsights.name 31 | -------------------------------------------------------------------------------- /infra/core/monitor/loganalytics.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | param tags object = {} 4 | 5 | resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-12-01-preview' = { 6 | name: name 7 | location: location 8 | tags: tags 9 | properties: any({ 10 | retentionInDays: 30 11 | features: { 12 | searchVersion: 1 13 | } 14 | sku: { 15 | name: 'PerGB2018' 16 | } 17 | }) 18 | } 19 | 20 | output id string = logAnalytics.id 21 | output name string = logAnalytics.name 22 | -------------------------------------------------------------------------------- /infra/core/monitor/monitoring.bicep: -------------------------------------------------------------------------------- 1 | param logAnalyticsName string 2 | param applicationInsightsName string 3 | param applicationInsightsDashboardName string 4 | param location string = resourceGroup().location 5 | param tags object = {} 6 | 7 | module logAnalytics 'loganalytics.bicep' = { 8 | name: 'loganalytics' 9 | params: { 10 | name: logAnalyticsName 11 | location: location 12 | tags: tags 13 | } 14 | } 15 | 16 | module applicationInsights 'applicationinsights.bicep' = { 17 | name: 'applicationinsights' 18 | params: { 19 | name: applicationInsightsName 20 | location: location 21 | tags: tags 22 | dashboardName: applicationInsightsDashboardName 23 | logAnalyticsWorkspaceId: logAnalytics.outputs.id 24 | } 25 | } 26 | 27 | output applicationInsightsConnectionString string = applicationInsights.outputs.connectionString 28 | output applicationInsightsInstrumentationKey string = applicationInsights.outputs.instrumentationKey 29 | output applicationInsightsName string = applicationInsights.outputs.name 30 | output logAnalyticsWorkspaceId string = logAnalytics.outputs.id 31 | output logAnalyticsWorkspaceName string = logAnalytics.outputs.name 32 | -------------------------------------------------------------------------------- /infra/core/signal-r/azure-signal-r.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | param tags object = {} 4 | 5 | param keyVaultName string 6 | 7 | resource signalR 'Microsoft.SignalRService/signalR@2022-02-01' = { 8 | name: name 9 | location: location 10 | tags: tags 11 | sku: { 12 | name: 'Free_F1' 13 | } 14 | kind: 'SignalR' 15 | properties: { 16 | features: [ 17 | { 18 | flag: 'ServiceMode' 19 | value: 'Serverless' 20 | } 21 | ] 22 | } 23 | } 24 | 25 | resource kv 'Microsoft.KeyVault/vaults@2022-07-01' existing = { 26 | name: keyVaultName 27 | } 28 | 29 | resource kvSecrets 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { 30 | name: 'AzureSignalRConnectionString' 31 | parent: kv 32 | properties: { 33 | value: listKeys(signalR.id, signalR.apiVersion).primaryConnectionString 34 | } 35 | } 36 | 37 | output signalRFullUrl string = signalR.properties.hostName 38 | output signalRSecretUri string = kvSecrets.properties.secretUri 39 | -------------------------------------------------------------------------------- /infra/core/sql-server/sql-azure.bicep: -------------------------------------------------------------------------------- 1 | param sqlServerName string 2 | param checkoutDbName string 3 | param menuDbName string 4 | param location string = resourceGroup().location 5 | param tags object = {} 6 | 7 | param keyVaultName string 8 | 9 | param sqlServerAdminLogin string 10 | @secure() 11 | param sqlServerAdminPassword string 12 | 13 | resource sqlServer 'Microsoft.Sql/servers@2022-05-01-preview' = { 14 | name: sqlServerName 15 | location: location 16 | tags: tags 17 | properties: { 18 | administratorLogin: sqlServerAdminLogin 19 | administratorLoginPassword: sqlServerAdminPassword 20 | } 21 | 22 | resource firewallRules 'firewallRules' = { 23 | name: 'AllowAllWindowsAzureIps' 24 | properties: { 25 | endIpAddress: '0.0.0.0' 26 | startIpAddress: '0.0.0.0' 27 | } 28 | } 29 | } 30 | 31 | resource checkoutDb 'Microsoft.Sql/servers/databases@2022-05-01-preview' = { 32 | name: checkoutDbName 33 | parent: sqlServer 34 | location: location 35 | tags: tags 36 | sku: { 37 | name: 'GP_S_Gen5_1' 38 | } 39 | properties: { 40 | collation: 'SQL_Latin1_General_CP1_CI_AS' 41 | createMode: 'Default' 42 | autoPauseDelay: 60 43 | minCapacity: 1 44 | } 45 | } 46 | 47 | var checkoutConnectionString = 'Data Source=tcp:${sqlServer.properties.fullyQualifiedDomainName},1433;Initial Catalog=${checkoutDbName};User ID=${sqlServerAdminLogin}@${sqlServer.name};Password=${sqlServerAdminPassword}' 48 | 49 | resource menuDb 'Microsoft.Sql/servers/databases@2022-05-01-preview' = { 50 | name: menuDbName 51 | parent: sqlServer 52 | location: location 53 | tags: tags 54 | sku: { 55 | name: 'GP_S_Gen5_1' 56 | } 57 | properties: { 58 | collation: 'SQL_Latin1_General_CP1_CI_AS' 59 | createMode: 'Default' 60 | autoPauseDelay: 60 61 | minCapacity: 1 62 | } 63 | } 64 | 65 | var menuConnectionString = 'Data Source=tcp:${sqlServer.properties.fullyQualifiedDomainName},1433;Initial Catalog=${menuDbName};User ID=${sqlServerAdminLogin};Password=${sqlServerAdminPassword}' 66 | 67 | // set the connection strings into key vault 68 | resource kv 'Microsoft.KeyVault/vaults@2022-07-01' existing = { 69 | name: keyVaultName 70 | } 71 | 72 | resource checkoutKvSecret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { 73 | name: '${checkoutDbName}ConnectionString' 74 | parent: kv 75 | properties: { 76 | value: checkoutConnectionString 77 | } 78 | } 79 | 80 | resource menuKvSecret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { 81 | name: '${menuDbName}ConnectionString' 82 | parent: kv 83 | properties: { 84 | value: menuConnectionString 85 | } 86 | } 87 | 88 | output sqlServerName string = sqlServer.name 89 | output sqlServerUrl string = sqlServer.properties.fullyQualifiedDomainName 90 | output sqlAdmin string = sqlServerAdminLogin 91 | output checkoutDbSecretUri string = checkoutKvSecret.properties.secretUri 92 | output mencuDbSecretUri string = menuKvSecret.properties.secretUri 93 | -------------------------------------------------------------------------------- /infra/core/storage/storage-account.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | param tags object = {} 4 | 5 | param allowBlobPublicAccess bool = true 6 | param containers array = [] 7 | param kind string = 'StorageV2' 8 | param minimumTlsVersion string = 'TLS1_2' 9 | param sku object = { name: 'Standard_LRS' } 10 | 11 | resource storage 'Microsoft.Storage/storageAccounts@2022-05-01' = { 12 | name: name 13 | location: location 14 | tags: tags 15 | kind: kind 16 | sku: sku 17 | properties: { 18 | minimumTlsVersion: minimumTlsVersion 19 | allowBlobPublicAccess: allowBlobPublicAccess 20 | networkAcls: { 21 | bypass: 'AzureServices' 22 | defaultAction: 'Allow' 23 | } 24 | } 25 | 26 | resource blobServices 'blobServices' = if (!empty(containers)) { 27 | name: 'default' 28 | resource container 'containers' = [for container in containers: { 29 | name: container.name 30 | properties: { 31 | publicAccess: contains(container, 'publicAccess') ? container.publicAccess : 'None' 32 | } 33 | }] 34 | } 35 | } 36 | 37 | output name string = storage.name 38 | output primaryEndpoints object = storage.properties.primaryEndpoints 39 | output pizzaImageContainerUrl string = '${storage.properties.primaryEndpoints.blob}/pizzaimages' 40 | -------------------------------------------------------------------------------- /infra/main.bicep: -------------------------------------------------------------------------------- 1 | targetScope = 'subscription' 2 | 3 | @minLength(1) 4 | @maxLength(50) 5 | @description('Name of the the environment which is used to generate a short unique hash used in all resources.') 6 | param environmentName string 7 | 8 | @description('The Azure principal id of the user or process running the install') 9 | param azurePrincipalId string 10 | 11 | @minLength(1) 12 | @description('Primary location for all resources') 13 | param location string 14 | 15 | 16 | param storageAccountName string = '' 17 | param profileName string = '' 18 | param endpointName string = '' 19 | param storageContainers array = [ 20 | { name: 'pizzaimages', publicAccess: 'Blob' } 21 | ] 22 | 23 | param sqlServerName string = '' 24 | param checkoutDbName string = 'pizzacart' 25 | param menuDbName string = 'pizzamenu' 26 | 27 | param sqlAdminLogin string = '' 28 | @secure() 29 | param sqlAdminPassword string = newGuid() 30 | 31 | param signalRName string = '' 32 | param keyVaultName string = '' 33 | param appConfigName string = '' 34 | 35 | // These are the key names for the Azure App Configuration. Unless you're planning on updating the web APIs, leave these as is 36 | param appConfigSignalRKeyName string = 'AzureSignalRConnectionString' 37 | param appConfigCartUrlKeyName string = 'cartUrl' 38 | param appConfigCheckoutDbKeyName string = 'CheckoutDb' 39 | param appConfigDaprCheckoutApiKeyName string = 'DaprAppId:PizzaConf:CheckoutApi' 40 | param appConfigDaprCheckoutApiValue string = 'checkoutapi' 41 | param appConfigDaprMenuApiKeyName string = 'DaprAppId:PizzaConf:MenuApi' 42 | param appConfigDaprMenuApiValue string = 'menuapi' 43 | param appConfigMenuDbKeyName string = 'menuDb' 44 | param appConfigMenuUrlKeyName string = 'menuUrl' 45 | param appConfigTrackingUrlKeyName string = 'trackingUrl' 46 | param appConfigCdnUrlKeyName string = 'cdnUrl' 47 | param appConfigImageStorageUrlKeyName string = 'imageStorageUrl' 48 | 49 | param functionAppName string = '' 50 | param functionAppPlanName string = '' 51 | 52 | param containerAppsEnvironmentName string = '' 53 | param containerRegistryName string = '' 54 | param logAnalyticsName string = '' 55 | 56 | var resourceToken = toLower(uniqueString(subscription().id, environmentName, location)) 57 | var tags = { 'azd-env-name': environmentName } 58 | var abbrs = loadJsonContent('abbreviations.json') 59 | 60 | resource rg 'Microsoft.Resources/resourceGroups@2021-04-01' = { 61 | name: '${abbrs.resourcesResourceGroups}${environmentName}' 62 | location: location 63 | tags: tags 64 | } 65 | 66 | // First create the key vault 67 | module keyVault './core/key-vault/key-vault.bicep' = { 68 | name: 'keyvault' 69 | scope: rg 70 | params: { 71 | name: !empty(keyVaultName) ? keyVaultName : '${abbrs.keyVaultVaults}${resourceToken}' 72 | location: location 73 | tags: tags 74 | azurePrincipalId: azurePrincipalId 75 | } 76 | } 77 | 78 | // Storage for website images 79 | module storage './core/storage/storage-account.bicep' = { 80 | name: 'storage' 81 | scope: rg 82 | params: { 83 | name: !empty(storageAccountName) ? storageAccountName : '${abbrs.storageStorageAccounts}${resourceToken}' 84 | location: location 85 | tags: tags 86 | containers: storageContainers 87 | } 88 | } 89 | 90 | // CDN endpoint for website images 91 | module cdn './core/cdn/endpoint.bicep' = { 92 | name: 'cdn' 93 | scope: rg 94 | params: { 95 | profileName: !empty(profileName) ? profileName : '${abbrs.cdnProfiles}${resourceToken}' 96 | endpointName: !empty(endpointName) ? endpointName : '${abbrs.cdnProfilesEndpoints}${resourceToken}' 97 | storageAccountHostName: replace(replace(storage.outputs.primaryEndpoints.blob, 'https://', ''), '/', '') 98 | location: location 99 | tags: tags 100 | } 101 | } 102 | 103 | module sql './core/sql-server/sql-azure.bicep' = { 104 | name: 'sql' 105 | scope: rg 106 | params: { 107 | location: location 108 | sqlServerName: !empty(sqlServerName) ? sqlServerName : '${abbrs.sqlServers}${resourceToken}' 109 | checkoutDbName: checkoutDbName 110 | menuDbName: menuDbName 111 | sqlServerAdminLogin: !empty(sqlAdminLogin) ? sqlAdminLogin : 'thepizzaman' 112 | sqlServerAdminPassword: sqlAdminPassword 113 | keyVaultName: keyVault.outputs.keyVaultName 114 | } 115 | } 116 | 117 | module signalr './core/signal-r/azure-signal-r.bicep' = { 118 | name: 'signalr' 119 | scope: rg 120 | params: { 121 | name: !empty(signalRName) ? signalRName : '${abbrs.signalRServiceSignalR}${resourceToken}' 122 | location: location 123 | tags: tags 124 | keyVaultName: keyVault.outputs.keyVaultName 125 | } 126 | } 127 | 128 | module appConfig './core/app-config/azure-app-config.bicep' = { 129 | name: 'appconfig' 130 | scope: rg 131 | params: { 132 | name: !empty(appConfigName) ? appConfigName : '${abbrs.appConfigurationConfigurationStores}${resourceToken}' 133 | location: location 134 | tags: tags 135 | azureSignalRKeyName: appConfigSignalRKeyName 136 | cartUrlKeyName: appConfigCartUrlKeyName 137 | cartUrlValue: 'http://localhost:3500' 138 | checkoutDbKeyName: appConfigCheckoutDbKeyName 139 | checkoutSecretUri: sql.outputs. checkoutDbSecretUri 140 | daprCheckoutApiKeyName: appConfigDaprCheckoutApiKeyName 141 | daprCheckoutApiValue: appConfigDaprCheckoutApiValue 142 | daprMenuApiKeyName: appConfigDaprMenuApiKeyName 143 | daprMenuApiValue: appConfigDaprMenuApiValue 144 | menuDbKeyName: appConfigMenuDbKeyName 145 | menuSecretUri: sql.outputs.mencuDbSecretUri 146 | menuUrlKeyName: appConfigMenuUrlKeyName 147 | menuUrlValue: 'http://localhost:3500' 148 | signalRSecretUri: signalr.outputs.signalRSecretUri 149 | imageCdnHostUrlKeyName: appConfigCdnUrlKeyName 150 | imageCdnHostUrlValue: cdn.outputs.hostName 151 | imageStorageUrlKeyName: appConfigImageStorageUrlKeyName 152 | imageStorageUrlValue: storage.outputs.pizzaImageContainerUrl 153 | } 154 | } 155 | 156 | module functions './core/host/functions.bicep' = { 157 | name: 'functions' 158 | scope: rg 159 | params: { 160 | location: location 161 | tags: tags 162 | appInsightsName: '${abbrs.insightsComponents}${resourceToken}' 163 | functionAppName: !empty(functionAppName) ? functionAppName : '${abbrs.webSitesFunctions}${resourceToken}' 164 | functionAppServicePlanName: !empty(functionAppPlanName) ? functionAppPlanName : '${abbrs.webSitesAppService}${resourceToken}' 165 | storageAccountName: '${abbrs.storageStorageAccounts}fn${resourceToken}' 166 | appConfigName: appConfig.outputs.appConfigName 167 | keyVaultName: keyVault.outputs.keyVaultName 168 | trackingUrlKeyName: appConfigTrackingUrlKeyName 169 | } 170 | } 171 | 172 | module logAnalytics './core/log-analytics/log-analytics.bicep' = { 173 | name: 'loganalytics' 174 | scope: rg 175 | params: { 176 | name: !empty(logAnalyticsName) ? logAnalyticsName : '${abbrs.operationalInsightsWorkspaces}${resourceToken}' 177 | location: location 178 | tags: tags 179 | } 180 | } 181 | 182 | module cae './core/container-apps/container-apps.bicep' = { 183 | name: 'cae' 184 | scope: rg 185 | params: { 186 | location: location 187 | tags: tags 188 | containerAppsEnvName: !empty(containerAppsEnvironmentName) ? containerAppsEnvironmentName : '${abbrs.appManagedEnvironments}${resourceToken}' 189 | containerRegistryName: !empty(containerRegistryName) ? containerRegistryName : '${abbrs.containerRegistryRegistries}${resourceToken}' 190 | logAnalyticsWorkspaceName: logAnalytics.outputs.logAnalyticsWorkspaceName 191 | } 192 | } 193 | 194 | output AZURE_LOCATION string = location 195 | output AZURE_STORAGE_ACCOUNT_NAME string = storage.outputs.name 196 | output AZURE_CDN_HOST_NAME string = cdn.outputs.hostName 197 | output AZURE_TENANT_ID string = tenant().tenantId 198 | output SQL_SERVER_URL string = sql.outputs.sqlServerUrl 199 | output SQL_ADMIN string = sql.outputs.sqlAdmin 200 | output SIGNALR_URL string = signalr.outputs.signalRFullUrl 201 | output APP_CONFIG_URL string = appConfig.outputs.appConfigUrl 202 | output AZURE_CONTAINER_REGISTRY_ENDPOINT string = cae.outputs.AZURE_CONTAINER_REGISTRY_ENDPOINT 203 | output AZURE_APP_CONFIG_NAME string = appConfig.outputs.appConfigName 204 | output AZURE_CONTAINER_APPS_ENVIRONMENT_NAME string = cae.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_NAME 205 | output AZURE_CONTAINER_REGISTRY_NAME string = cae.outputs.AZURE_CONTAINER_REGISTRY_NAME 206 | output AZURE_KEYVAULT_NAME string = keyVault.outputs.keyVaultName 207 | -------------------------------------------------------------------------------- /infra/main.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "environmentName": { 6 | "value": "${AZURE_ENV_NAME}" 7 | }, 8 | "location": { 9 | "value": "${AZURE_LOCATION}" 10 | }, 11 | "azurePrincipalId": { 12 | "value": "${AZURE_PRINCIPAL_ID}" 13 | } 14 | } 15 | } --------------------------------------------------------------------------------