├── .devcontainer ├── Dockerfile ├── data │ └── ContosoPizza.dacpac ├── devcontainer.json ├── docker-compose.yml └── scripts │ ├── installSQLtools.sh │ └── postCreateCommand.sh ├── .gitattributes ├── .github └── workflows │ └── dotnet.yml ├── .gitignore ├── .tours ├── 1-getting-started.tour ├── 2-existing-databases.tour ├── 3-web-sites.tour ├── 4-database-providers.tour ├── 5-performance-tips.tour └── media │ ├── 1-entity-diagram.png │ ├── 1-products-table.png │ ├── 1-refresh-explorer.png │ ├── 1-sql-server.png │ ├── 1-workspace-with-files.png │ ├── 2-integrated-terminal.png │ ├── 2-models-new-file.png │ ├── 3-integrated-terminal.png │ ├── 4-cosmos-db.png │ ├── 4-ef-core-architecture.png │ ├── 4-integrated-terminal.png │ ├── 4-postgres-output.png │ ├── readme-launch-codespace.gif │ └── readme-launch-codetour.gif ├── .vscode ├── extensions.json ├── settings.json └── tasks.json ├── CODE_OF_CONDUCT.md ├── LICENSE ├── LICENSE-CODE ├── README.md ├── SECURITY.md ├── notes ├── 1-getting-started │ ├── ContosoPizzaContext.cs │ ├── Customer.cs │ ├── Order.cs │ ├── OrderDetail.cs │ ├── Product.cs │ ├── Program-snippets.cs │ ├── connection-strings.md │ ├── entity-diagram.md │ └── script.md ├── 2-existing-databases │ ├── Customer.cs │ ├── Program.cs │ ├── connection-strings-and-notes.md │ └── script.md ├── 3-web-sites │ ├── notes-and-snippets.md │ └── script.md ├── 4-database-providers │ ├── connection-strings-and-notes.md │ └── script.md ├── 5-performance-tips │ ├── connection-strings-and-notes.md │ └── script.md ├── series-outline.md └── supplemental │ └── script.md └── parts ├── 1-getting-started └── ContosoPizza │ ├── ContosoPizza.csproj │ └── Program.cs ├── 2-existing-databases └── ContosoPizza │ ├── ContosoPizza.csproj │ └── Program.cs ├── 3-web-sites └── ContosoPizza │ ├── ContosoPizza.csproj │ ├── Data │ └── ContosoPizzaContext.cs │ ├── Models │ ├── Customer.cs │ ├── Order.cs │ ├── OrderDetail.cs │ └── Product.cs │ ├── Pages │ ├── Error.cshtml │ ├── Error.cshtml.cs │ ├── Index.cshtml │ ├── Index.cshtml.cs │ ├── Privacy.cshtml │ ├── Privacy.cshtml.cs │ ├── Shared │ │ ├── _Layout.cshtml │ │ ├── _Layout.cshtml.css │ │ └── _ValidationScriptsPartial.cshtml │ ├── _ViewImports.cshtml │ └── _ViewStart.cshtml │ ├── Program.cs │ ├── Properties │ └── launchSettings.json │ ├── appsettings.Development.json │ ├── appsettings.json │ └── wwwroot │ ├── css │ └── site.css │ ├── favicon.ico │ ├── js │ └── site.js │ └── lib │ ├── bootstrap │ ├── LICENSE │ └── dist │ │ ├── css │ │ ├── bootstrap-grid.css │ │ ├── bootstrap-grid.css.map │ │ ├── bootstrap-grid.min.css │ │ ├── bootstrap-grid.min.css.map │ │ ├── bootstrap-grid.rtl.css │ │ ├── bootstrap-grid.rtl.css.map │ │ ├── bootstrap-grid.rtl.min.css │ │ ├── bootstrap-grid.rtl.min.css.map │ │ ├── bootstrap-reboot.css │ │ ├── bootstrap-reboot.css.map │ │ ├── bootstrap-reboot.min.css │ │ ├── bootstrap-reboot.min.css.map │ │ ├── bootstrap-reboot.rtl.css │ │ ├── bootstrap-reboot.rtl.css.map │ │ ├── bootstrap-reboot.rtl.min.css │ │ ├── bootstrap-reboot.rtl.min.css.map │ │ ├── bootstrap-utilities.css │ │ ├── bootstrap-utilities.css.map │ │ ├── bootstrap-utilities.min.css │ │ ├── bootstrap-utilities.min.css.map │ │ ├── bootstrap-utilities.rtl.css │ │ ├── bootstrap-utilities.rtl.css.map │ │ ├── bootstrap-utilities.rtl.min.css │ │ ├── bootstrap-utilities.rtl.min.css.map │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ ├── bootstrap.min.css │ │ ├── bootstrap.min.css.map │ │ ├── bootstrap.rtl.css │ │ ├── bootstrap.rtl.css.map │ │ ├── bootstrap.rtl.min.css │ │ └── bootstrap.rtl.min.css.map │ │ └── js │ │ ├── bootstrap.bundle.js │ │ ├── bootstrap.bundle.js.map │ │ ├── bootstrap.bundle.min.js │ │ ├── bootstrap.bundle.min.js.map │ │ ├── bootstrap.esm.js │ │ ├── bootstrap.esm.js.map │ │ ├── bootstrap.esm.min.js │ │ ├── bootstrap.esm.min.js.map │ │ ├── bootstrap.js │ │ ├── bootstrap.js.map │ │ ├── bootstrap.min.js │ │ └── bootstrap.min.js.map │ ├── jquery-validation-unobtrusive │ ├── LICENSE.txt │ ├── jquery.validate.unobtrusive.js │ └── jquery.validate.unobtrusive.min.js │ ├── jquery-validation │ ├── LICENSE.md │ └── dist │ │ ├── additional-methods.js │ │ ├── additional-methods.min.js │ │ ├── jquery.validate.js │ │ └── jquery.validate.min.js │ └── jquery │ ├── LICENSE.txt │ └── dist │ ├── jquery.js │ ├── jquery.min.js │ └── jquery.min.map ├── 4-database-providers └── ContosoPizza │ ├── ContosoPizza.csproj │ ├── Data │ └── ContosoPizzaContext.cs │ ├── Models │ ├── Customer.cs │ ├── Order.cs │ ├── OrderDetail.cs │ └── Product.cs │ └── Program.cs └── 5-performance-tips └── ContosoPizza ├── ContosoPizza.csproj ├── Data └── ContosoPizzaContext.cs ├── Models ├── Customer.cs ├── Order.cs ├── OrderDetail.cs └── Product.cs ├── Pages ├── Customers │ ├── Create.cshtml │ ├── Create.cshtml.cs │ ├── Delete.cshtml │ ├── Delete.cshtml.cs │ ├── Details.cshtml │ ├── Details.cshtml.cs │ ├── Edit.cshtml │ ├── Edit.cshtml.cs │ ├── Index.cshtml │ └── Index.cshtml.cs ├── Error.cshtml ├── Error.cshtml.cs ├── Index.cshtml ├── Index.cshtml.cs ├── Privacy.cshtml ├── Privacy.cshtml.cs ├── Products │ ├── Details.cshtml │ └── Details.cshtml.cs ├── Shared │ ├── _Layout.cshtml │ ├── _Layout.cshtml.css │ └── _ValidationScriptsPartial.cshtml ├── _ViewImports.cshtml └── _ViewStart.cshtml ├── Program.cs ├── Properties └── launchSettings.json ├── appsettings.Development.json ├── appsettings.json └── wwwroot ├── css └── site.css ├── favicon.ico ├── js └── site.js └── lib ├── bootstrap ├── LICENSE └── dist │ ├── css │ ├── bootstrap-grid.css │ ├── bootstrap-grid.css.map │ ├── bootstrap-grid.min.css │ ├── bootstrap-grid.min.css.map │ ├── bootstrap-grid.rtl.css │ ├── bootstrap-grid.rtl.css.map │ ├── bootstrap-grid.rtl.min.css │ ├── bootstrap-grid.rtl.min.css.map │ ├── bootstrap-reboot.css │ ├── bootstrap-reboot.css.map │ ├── bootstrap-reboot.min.css │ ├── bootstrap-reboot.min.css.map │ ├── bootstrap-reboot.rtl.css │ ├── bootstrap-reboot.rtl.css.map │ ├── bootstrap-reboot.rtl.min.css │ ├── bootstrap-reboot.rtl.min.css.map │ ├── bootstrap-utilities.css │ ├── bootstrap-utilities.css.map │ ├── bootstrap-utilities.min.css │ ├── bootstrap-utilities.min.css.map │ ├── bootstrap-utilities.rtl.css │ ├── bootstrap-utilities.rtl.css.map │ ├── bootstrap-utilities.rtl.min.css │ ├── bootstrap-utilities.rtl.min.css.map │ ├── bootstrap.css │ ├── bootstrap.css.map │ ├── bootstrap.min.css │ ├── bootstrap.min.css.map │ ├── bootstrap.rtl.css │ ├── bootstrap.rtl.css.map │ ├── bootstrap.rtl.min.css │ └── bootstrap.rtl.min.css.map │ └── js │ ├── bootstrap.bundle.js │ ├── bootstrap.bundle.js.map │ ├── bootstrap.bundle.min.js │ ├── bootstrap.bundle.min.js.map │ ├── bootstrap.esm.js │ ├── bootstrap.esm.js.map │ ├── bootstrap.esm.min.js │ ├── bootstrap.esm.min.js.map │ ├── bootstrap.js │ ├── bootstrap.js.map │ ├── bootstrap.min.js │ └── bootstrap.min.js.map ├── jquery-validation-unobtrusive ├── LICENSE.txt ├── jquery.validate.unobtrusive.js └── jquery.validate.unobtrusive.min.js ├── jquery-validation ├── LICENSE.md └── dist │ ├── additional-methods.js │ ├── additional-methods.min.js │ ├── jquery.validate.js │ └── jquery.validate.min.js └── jquery ├── LICENSE.txt └── dist ├── jquery.js ├── jquery.min.js └── jquery.min.map /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # [Choice] .NET version: 6.0-focal, 5.0-focal, 3.1-focal 2 | ARG VARIANT="6.0-focal" 3 | FROM mcr.microsoft.com/vscode/devcontainers/dotnet:0-${VARIANT} 4 | 5 | # [Choice] Node.js version: none, lts/*, 16, 14, 12, 10 6 | ARG NODE_VERSION="none" 7 | RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi 8 | 9 | # Install SQL Tools: SQLPackage and sqlcmd 10 | COPY scripts/installSQLtools.sh installSQLtools.sh 11 | RUN bash ./installSQLtools.sh \ 12 | && apt-get clean -y && rm -rf /var/lib/apt/lists/* /tmp/library-scripts 13 | 14 | # [Optional] Uncomment this section to install additional OS packages. 15 | # RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 16 | # && apt-get -y install --no-install-recommends 17 | 18 | # [Optional] Uncomment this line to install global node packages. 19 | # RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g " 2>&1 20 | 21 | # Add .NET global tools to path 22 | RUN echo "export PATH=\"$PATH:/root/.dotnet/tools\"" >> ~/.bashrc 23 | 24 | # Generate the dev cert 25 | RUN dotnet dev-certs https -------------------------------------------------------------------------------- /.devcontainer/data/ContosoPizza.dacpac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDocs/ef-core-for-beginners/b846adad4ef68e7dba4468e89c659dcf0661c4c7/.devcontainer/data/ContosoPizza.dacpac -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: 2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.224.3/containers/dotnet-mssql 3 | { 4 | "name": "Entity Framework Core for Beginners", 5 | "dockerComposeFile": "docker-compose.yml", 6 | "service": "app", 7 | "workspaceFolder": "/workspace", 8 | 9 | // Set *default* container specific settings.json values on container create. 10 | "settings": { 11 | "mssql.connections": [ 12 | { 13 | "server": "localhost,1433", 14 | "database": "", 15 | "authenticationType": "SqlLogin", 16 | "user": "sa", 17 | "password": "P@ssw0rd", 18 | "emptyPasswordInput": false, 19 | "savePassword": true, 20 | "profileName": "mssql-container", 21 | "encrypt": false 22 | } 23 | ] 24 | }, 25 | 26 | // Add the IDs of extensions you want installed when the container is created. 27 | "extensions": [ 28 | "ms-dotnettools.csharp", 29 | "ms-mssql.mssql", 30 | "ckolkman.vscode-postgres", 31 | "vsls-contrib.codetour" 32 | ], 33 | 34 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 35 | "forwardPorts": [1433,5432], 36 | 37 | "portsAttributes": { 38 | "5266": { 39 | "label": "ContosoPizza HTTP", 40 | "onAutoForward": "silent" 41 | }, 42 | "7244": { 43 | "label": "ContosoPizza HTTPS", 44 | "onAutoForward": "notify", 45 | "protocol": "https" 46 | } 47 | }, 48 | 49 | // [Optional] To reuse your local HTTPS dev cert: 50 | // 51 | // 1. Export it locally using this command: 52 | // * Windows PowerShell: 53 | // dotnet dev-certs https --trust; dotnet dev-certs https -ep "$env:USERPROFILE/.aspnet/https/aspnetapp.pfx" -p "SecurePwdGoesHere" 54 | // * macOS/Linux terminal: 55 | // dotnet dev-certs https --trust; dotnet dev-certs https -ep "${HOME}/.aspnet/https/aspnetapp.pfx" -p "SecurePwdGoesHere" 56 | // 57 | // 2. Uncomment these 'remoteEnv' lines: 58 | // "remoteEnv": { 59 | // "ASPNETCORE_Kestrel__Certificates__Default__Password": "SecurePwdGoesHere", 60 | // "ASPNETCORE_Kestrel__Certificates__Default__Path": "/home/vscode/.aspnet/https/aspnetapp.pfx", 61 | // }, 62 | // 63 | // 3. Next, copy your certificate into the container: 64 | // 1. Start the container 65 | // 2. Drag ~/.aspnet/https/aspnetapp.pfx into the root of the file explorer 66 | // 3. Open a terminal in VS Code and run "mkdir -p /home/vscode/.aspnet/https && mv aspnetapp.pfx /home/vscode/.aspnet/https" 67 | 68 | // postCreateCommand.sh parameters: $1=SA password, $2=dacpac path, $3=sql script(s) path 69 | "postCreateCommand": "bash .devcontainer/scripts/postCreateCommand.sh 'P@ssw0rd' './.devcontainer/data/' './.devcontainer/scripts/'", 70 | "features": { 71 | // "azure-cli": "latest" 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /.devcontainer/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | app: 5 | build: 6 | context: . 7 | dockerfile: Dockerfile 8 | args: 9 | # Update 'VARIANT' to pick a version of .NET: 3.1-focal, 5.0-focal, 6.0-focal 10 | VARIANT: "6.0-focal" 11 | # Optional version of Node.js 12 | NODE_VERSION: "none" 13 | 14 | volumes: 15 | - ..:/workspace:cached 16 | - ./persisted-data/.aspnet:/root/.aspnet/ 17 | 18 | 19 | # Overrides default command so things don't shut down after the process ends. 20 | command: sleep infinity 21 | 22 | # Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function. 23 | network_mode: service:db 24 | 25 | # Uncomment the next line to use a non-root user for all processes. 26 | # user: vscode 27 | 28 | # Use "forwardPorts" in **devcontainer.json** to forward an app port locally. 29 | # (Adding the "ports" property to this file will not forward from a Codespace.) 30 | 31 | db: 32 | image: mcr.microsoft.com/mssql/server:2019-latest 33 | restart: unless-stopped 34 | environment: 35 | SA_PASSWORD: P@ssw0rd 36 | ACCEPT_EULA: Y 37 | 38 | # Add "forwardPorts": ["1433"] to **devcontainer.json** to forward MSSQL locally. 39 | # (Adding the "ports" property to this file will not forward from a Codespace.) 40 | 41 | postgres: 42 | image: postgres 43 | restart: always 44 | environment: 45 | POSTGRES_PASSWORD: "P@ssw0rd" 46 | network_mode: service:db 47 | 48 | 49 | -------------------------------------------------------------------------------- /.devcontainer/scripts/installSQLtools.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "Installing mssql-tools" 3 | curl -sSL https://packages.microsoft.com/keys/microsoft.asc | (OUT=$(apt-key add - 2>&1) || echo $OUT) 4 | DISTRO=$(lsb_release -is | tr '[:upper:]' '[:lower:]') 5 | CODENAME=$(lsb_release -cs) 6 | echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-${DISTRO}-${CODENAME}-prod ${CODENAME} main" > /etc/apt/sources.list.d/microsoft.list 7 | apt-get update 8 | ACCEPT_EULA=Y apt-get -y install unixodbc-dev msodbcsql17 libunwind8 mssql-tools 9 | 10 | echo "Installing sqlpackage" 11 | curl -sSL -o sqlpackage.zip "https://aka.ms/sqlpackage-linux" 12 | mkdir /opt/sqlpackage 13 | unzip sqlpackage.zip -d /opt/sqlpackage 14 | rm sqlpackage.zip 15 | chmod a+x /opt/sqlpackage/sqlpackage 16 | 17 | echo "Install Sqlite tools" 18 | apt-get -y install sqlite 19 | -------------------------------------------------------------------------------- /.devcontainer/scripts/postCreateCommand.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | dacpac="false" 3 | sqlfiles="false" 4 | SApassword=$1 5 | dacpath=$2 6 | sqlpath=$3 7 | 8 | echo "SELECT * FROM SYS.DATABASES" | dd of=testsqlconnection.sql 9 | for i in {1..60}; 10 | do 11 | /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P $SApassword -d master -i testsqlconnection.sql > /dev/null 12 | if [ $? -eq 0 ] 13 | then 14 | echo "SQL server ready" 15 | break 16 | else 17 | echo "Not ready yet..." 18 | sleep 1 19 | fi 20 | done 21 | rm testsqlconnection.sql 22 | 23 | for f in $dacpath/* 24 | do 25 | if [ $f == $dacpath/*".dacpac" ] 26 | then 27 | dacpac="true" 28 | echo "Found dacpac $f" 29 | fi 30 | done 31 | 32 | for f in $sqlpath/* 33 | do 34 | if [ $f == $sqlpath/*".sql" ] 35 | then 36 | sqlfiles="true" 37 | echo "Found SQL file $f" 38 | fi 39 | done 40 | 41 | if [ $sqlfiles == "true" ] 42 | then 43 | for f in $sqlpath/* 44 | do 45 | if [ $f == $sqlpath/*".sql" ] 46 | then 47 | echo "Executing $f" 48 | /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P $SApassword -d master -i $f 49 | fi 50 | done 51 | fi 52 | 53 | if [ $dacpac == "true" ] 54 | then 55 | for f in $dacpath/* 56 | do 57 | if [ $f == $dacpath/*".dacpac" ] 58 | then 59 | dbname=$(basename $f ".dacpac") 60 | echo "Deploying dacpac $f" 61 | /opt/sqlpackage/sqlpackage /Action:Publish /SourceFile:$f /TargetServerName:localhost /TargetDatabaseName:$dbname /TargetUser:sa /TargetPassword:$SApassword /TargetEncryptConnection:False 62 | fi 63 | done 64 | fi 65 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | *.{cmd,[cC][mM][dD]} text eol=crlf 3 | *.{bat,[bB][aA][tT]} text eol=crlf -------------------------------------------------------------------------------- /.github/workflows/dotnet.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | pull_request: 6 | branches: [ main ] 7 | paths: 8 | - '**.cs' 9 | - '**.csproj' 10 | - '**.cshtml' 11 | - '**.css' 12 | 13 | env: 14 | DOTNET_VERSION: '6.0.x' # The .NET SDK version to use 15 | 16 | jobs: 17 | build: 18 | 19 | name: Build All Projects 20 | runs-on: ubuntu-latest 21 | strategy: 22 | fail-fast: false 23 | matrix: 24 | project: 25 | - 1-getting-started 26 | - 2-existing-databases 27 | - 3-web-sites 28 | - 4-database-providers 29 | - 5-performance-tips 30 | 31 | steps: 32 | - uses: actions/checkout@v2 33 | - name: Setup .NET 34 | uses: actions/setup-dotnet@v2 35 | with: 36 | dotnet-version: ${{ env.DOTNET_VERSION }} 37 | 38 | - name: Build Step - ${{ matrix.project }} 39 | run: dotnet build ./parts/${{ matrix.project }}/ContosoPizza/ContosoPizza.csproj 40 | -------------------------------------------------------------------------------- /.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 | persisted-data/ 7 | 8 | # User-specific files 9 | *.rsuser 10 | *.suo 11 | *.user 12 | *.userosscache 13 | *.sln.docstates 14 | 15 | # User-specific files (MonoDevelop/Xamarin Studio) 16 | *.userprefs 17 | 18 | # Mono auto generated files 19 | mono_crash.* 20 | 21 | # Build results 22 | [Dd]ebug/ 23 | [Dd]ebugPublic/ 24 | [Rr]elease/ 25 | [Rr]eleases/ 26 | x64/ 27 | x86/ 28 | [Aa][Rr][Mm]/ 29 | [Aa][Rr][Mm]64/ 30 | bld/ 31 | [Bb]in/ 32 | [Oo]bj/ 33 | [Ll]og/ 34 | [Ll]ogs/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # StyleCop 67 | StyleCopReport.xml 68 | 69 | # Files built by Visual Studio 70 | *_i.c 71 | *_p.c 72 | *_h.h 73 | *.ilk 74 | *.meta 75 | *.obj 76 | *.iobj 77 | *.pch 78 | *.pdb 79 | *.ipdb 80 | *.pgc 81 | *.pgd 82 | *.rsp 83 | *.sbr 84 | *.tlb 85 | *.tli 86 | *.tlh 87 | *.tmp 88 | *.tmp_proj 89 | *_wpftmp.csproj 90 | *.log 91 | *.vspscc 92 | *.vssscc 93 | .builds 94 | *.pidb 95 | *.svclog 96 | *.scc 97 | 98 | # Chutzpah Test files 99 | _Chutzpah* 100 | 101 | # Visual C++ cache files 102 | ipch/ 103 | *.aps 104 | *.ncb 105 | *.opendb 106 | *.opensdf 107 | *.sdf 108 | *.cachefile 109 | *.VC.db 110 | *.VC.VC.opendb 111 | 112 | # Visual Studio profiler 113 | *.psess 114 | *.vsp 115 | *.vspx 116 | *.sap 117 | 118 | # Visual Studio Trace Files 119 | *.e2e 120 | 121 | # TFS 2012 Local Workspace 122 | $tf/ 123 | 124 | # Guidance Automation Toolkit 125 | *.gpState 126 | 127 | # ReSharper is a .NET coding add-in 128 | _ReSharper*/ 129 | *.[Rr]e[Ss]harper 130 | *.DotSettings.user 131 | 132 | # TeamCity is a build add-in 133 | _TeamCity* 134 | 135 | # DotCover is a Code Coverage Tool 136 | *.dotCover 137 | 138 | # AxoCover is a Code Coverage Tool 139 | .axoCover/* 140 | !.axoCover/settings.json 141 | 142 | # Visual Studio code coverage results 143 | *.coverage 144 | *.coveragexml 145 | 146 | # NCrunch 147 | _NCrunch_* 148 | .*crunch*.local.xml 149 | nCrunchTemp_* 150 | 151 | # MightyMoose 152 | *.mm.* 153 | AutoTest.Net/ 154 | 155 | # Web workbench (sass) 156 | .sass-cache/ 157 | 158 | # Installshield output folder 159 | [Ee]xpress/ 160 | 161 | # DocProject is a documentation generator add-in 162 | DocProject/buildhelp/ 163 | DocProject/Help/*.HxT 164 | DocProject/Help/*.HxC 165 | DocProject/Help/*.hhc 166 | DocProject/Help/*.hhk 167 | DocProject/Help/*.hhp 168 | DocProject/Help/Html2 169 | DocProject/Help/html 170 | 171 | # Click-Once directory 172 | publish/ 173 | 174 | # Publish Web Output 175 | *.[Pp]ublish.xml 176 | *.azurePubxml 177 | # Note: Comment the next line if you want to checkin your web deploy settings, 178 | # but database connection strings (with potential passwords) will be unencrypted 179 | *.pubxml 180 | *.publishproj 181 | 182 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 183 | # checkin your Azure Web App publish settings, but sensitive information contained 184 | # in these scripts will be unencrypted 185 | PublishScripts/ 186 | 187 | # NuGet Packages 188 | *.nupkg 189 | # NuGet Symbol Packages 190 | *.snupkg 191 | # The packages folder can be ignored because of Package Restore 192 | **/[Pp]ackages/* 193 | # except build/, which is used as an MSBuild target. 194 | !**/[Pp]ackages/build/ 195 | # Uncomment if necessary however generally it will be regenerated when needed 196 | #!**/[Pp]ackages/repositories.config 197 | # NuGet v3's project.json files produces more ignorable files 198 | *.nuget.props 199 | *.nuget.targets 200 | 201 | # Microsoft Azure Build Output 202 | csx/ 203 | *.build.csdef 204 | 205 | # Microsoft Azure Emulator 206 | ecf/ 207 | rcf/ 208 | 209 | # Windows Store app package directories and files 210 | AppPackages/ 211 | BundleArtifacts/ 212 | Package.StoreAssociation.xml 213 | _pkginfo.txt 214 | *.appx 215 | *.appxbundle 216 | *.appxupload 217 | 218 | # Visual Studio cache files 219 | # files ending in .cache can be ignored 220 | *.[Cc]ache 221 | # but keep track of directories ending in .cache 222 | !?*.[Cc]ache/ 223 | 224 | # Others 225 | ClientBin/ 226 | ~$* 227 | *~ 228 | *.dbmdl 229 | *.dbproj.schemaview 230 | *.jfm 231 | *.pfx 232 | *.publishsettings 233 | orleans.codegen.cs 234 | 235 | # Including strong name files can present a security risk 236 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 237 | #*.snk 238 | 239 | # Since there are multiple workflows, uncomment next line to ignore bower_components 240 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 241 | #bower_components/ 242 | 243 | # RIA/Silverlight projects 244 | Generated_Code/ 245 | 246 | # Backup & report files from converting an old project file 247 | # to a newer Visual Studio version. Backup files are not needed, 248 | # because we have git ;-) 249 | _UpgradeReport_Files/ 250 | Backup*/ 251 | UpgradeLog*.XML 252 | UpgradeLog*.htm 253 | ServiceFabricBackup/ 254 | *.rptproj.bak 255 | 256 | # SQL Server files 257 | *.mdf 258 | *.ldf 259 | *.ndf 260 | 261 | # Business Intelligence projects 262 | *.rdl.data 263 | *.bim.layout 264 | *.bim_*.settings 265 | *.rptproj.rsuser 266 | *- [Bb]ackup.rdl 267 | *- [Bb]ackup ([0-9]).rdl 268 | *- [Bb]ackup ([0-9][0-9]).rdl 269 | 270 | # Microsoft Fakes 271 | FakesAssemblies/ 272 | 273 | # GhostDoc plugin setting file 274 | *.GhostDoc.xml 275 | 276 | # Node.js Tools for Visual Studio 277 | .ntvs_analysis.dat 278 | node_modules/ 279 | 280 | # Visual Studio 6 build log 281 | *.plg 282 | 283 | # Visual Studio 6 workspace options file 284 | *.opt 285 | 286 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 287 | *.vbw 288 | 289 | # Visual Studio LightSwitch build output 290 | **/*.HTMLClient/GeneratedArtifacts 291 | **/*.DesktopClient/GeneratedArtifacts 292 | **/*.DesktopClient/ModelManifest.xml 293 | **/*.Server/GeneratedArtifacts 294 | **/*.Server/ModelManifest.xml 295 | _Pvt_Extensions 296 | 297 | # Paket dependency manager 298 | .paket/paket.exe 299 | paket-files/ 300 | 301 | # FAKE - F# Make 302 | .fake/ 303 | 304 | # CodeRush personal settings 305 | .cr/personal 306 | 307 | # Python Tools for Visual Studio (PTVS) 308 | __pycache__/ 309 | *.pyc 310 | 311 | # Cake - Uncomment if you are using it 312 | # tools/** 313 | # !tools/packages.config 314 | 315 | # Tabs Studio 316 | *.tss 317 | 318 | # Telerik's JustMock configuration file 319 | *.jmconfig 320 | 321 | # BizTalk build output 322 | *.btp.cs 323 | *.btm.cs 324 | *.odx.cs 325 | *.xsd.cs 326 | 327 | # OpenCover UI analysis results 328 | OpenCover/ 329 | 330 | # Azure Stream Analytics local run output 331 | ASALocalRun/ 332 | 333 | # MSBuild Binary and Structured Log 334 | *.binlog 335 | 336 | # NVidia Nsight GPU debugger configuration file 337 | *.nvuser 338 | 339 | # MFractors (Xamarin productivity tool) working folder 340 | .mfractor/ 341 | 342 | # Local History for Visual Studio 343 | .localhistory/ 344 | 345 | # BeatPulse healthcheck temp database 346 | healthchecksdb 347 | 348 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 349 | MigrationBackup/ 350 | 351 | # Ionide (cross platform F# VS Code tools) working folder 352 | .ionide/ 353 | -------------------------------------------------------------------------------- /.tours/media/1-entity-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDocs/ef-core-for-beginners/b846adad4ef68e7dba4468e89c659dcf0661c4c7/.tours/media/1-entity-diagram.png -------------------------------------------------------------------------------- /.tours/media/1-products-table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDocs/ef-core-for-beginners/b846adad4ef68e7dba4468e89c659dcf0661c4c7/.tours/media/1-products-table.png -------------------------------------------------------------------------------- /.tours/media/1-refresh-explorer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDocs/ef-core-for-beginners/b846adad4ef68e7dba4468e89c659dcf0661c4c7/.tours/media/1-refresh-explorer.png -------------------------------------------------------------------------------- /.tours/media/1-sql-server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDocs/ef-core-for-beginners/b846adad4ef68e7dba4468e89c659dcf0661c4c7/.tours/media/1-sql-server.png -------------------------------------------------------------------------------- /.tours/media/1-workspace-with-files.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDocs/ef-core-for-beginners/b846adad4ef68e7dba4468e89c659dcf0661c4c7/.tours/media/1-workspace-with-files.png -------------------------------------------------------------------------------- /.tours/media/2-integrated-terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDocs/ef-core-for-beginners/b846adad4ef68e7dba4468e89c659dcf0661c4c7/.tours/media/2-integrated-terminal.png -------------------------------------------------------------------------------- /.tours/media/2-models-new-file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDocs/ef-core-for-beginners/b846adad4ef68e7dba4468e89c659dcf0661c4c7/.tours/media/2-models-new-file.png -------------------------------------------------------------------------------- /.tours/media/3-integrated-terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDocs/ef-core-for-beginners/b846adad4ef68e7dba4468e89c659dcf0661c4c7/.tours/media/3-integrated-terminal.png -------------------------------------------------------------------------------- /.tours/media/4-cosmos-db.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDocs/ef-core-for-beginners/b846adad4ef68e7dba4468e89c659dcf0661c4c7/.tours/media/4-cosmos-db.png -------------------------------------------------------------------------------- /.tours/media/4-ef-core-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDocs/ef-core-for-beginners/b846adad4ef68e7dba4468e89c659dcf0661c4c7/.tours/media/4-ef-core-architecture.png -------------------------------------------------------------------------------- /.tours/media/4-integrated-terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDocs/ef-core-for-beginners/b846adad4ef68e7dba4468e89c659dcf0661c4c7/.tours/media/4-integrated-terminal.png -------------------------------------------------------------------------------- /.tours/media/4-postgres-output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDocs/ef-core-for-beginners/b846adad4ef68e7dba4468e89c659dcf0661c4c7/.tours/media/4-postgres-output.png -------------------------------------------------------------------------------- /.tours/media/readme-launch-codespace.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDocs/ef-core-for-beginners/b846adad4ef68e7dba4468e89c659dcf0661c4c7/.tours/media/readme-launch-codespace.gif -------------------------------------------------------------------------------- /.tours/media/readme-launch-codetour.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDocs/ef-core-for-beginners/b846adad4ef68e7dba4468e89c659dcf0661c4c7/.tours/media/readme-launch-codetour.gif -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-dotnettools.csharp", 4 | "ms-mssql.mssql", 5 | "ckolkman.vscode-postgres", 6 | "vsls-contrib.codetour" 7 | ], 8 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "build", 8 | "command": "dotnet", 9 | "type": "shell", 10 | "args": [ 11 | "build", 12 | // Ask dotnet build to generate full paths for file names. 13 | "/property:GenerateFullPaths=true", 14 | // Do not generate summary otherwise it leads to duplicate errors in Problems panel 15 | "/consoleloggerparameters:NoSummary" 16 | ], 17 | "group": "build", 18 | "presentation": { 19 | "reveal": "silent" 20 | }, 21 | "problemMatcher": "$msCompile" 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /LICENSE-CODE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 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 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | -------------------------------------------------------------------------------- /notes/1-getting-started/ContosoPizzaContext.cs: -------------------------------------------------------------------------------- 1 | using ContosoPizza.Models; 2 | using Microsoft.EntityFrameworkCore; 3 | 4 | namespace ContosoPizza.Data; 5 | 6 | public class ContosoPizzaContext : DbContext 7 | { 8 | public DbSet Customers { get; set; } = null!; 9 | public DbSet Orders { get; set; } = null!; 10 | public DbSet Products { get; set; } = null!; 11 | public DbSet OrderDetails { get; set; } = null!; 12 | 13 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 14 | { 15 | optionsBuilder.UseSqlServer(@"Connection String Here"); 16 | } 17 | } -------------------------------------------------------------------------------- /notes/1-getting-started/Customer.cs: -------------------------------------------------------------------------------- 1 | namespace ContosoPizza.Models; 2 | 3 | public class Customer 4 | { 5 | public int Id { get; set; } 6 | public string FirstName { get; set; } = null!; 7 | public string LastName { get; set; } = null!; 8 | public string? Address { get; set; } 9 | public string? Phone { get; set; } 10 | public string? Email { get; set; } 11 | 12 | public ICollection Orders { get; set; } = null!; 13 | } 14 | -------------------------------------------------------------------------------- /notes/1-getting-started/Order.cs: -------------------------------------------------------------------------------- 1 | namespace ContosoPizza.Models; 2 | 3 | public class Order 4 | { 5 | public int Id { get; set; } 6 | public DateTime OrderPlaced { get; set; } 7 | public DateTime? OrderFulfilled { get; set; } 8 | public int CustomerId { get; set; } 9 | 10 | public Customer Customer { get; set; } = null!; 11 | public ICollection OrderDetails { get; set; } = null!; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /notes/1-getting-started/OrderDetail.cs: -------------------------------------------------------------------------------- 1 | namespace ContosoPizza.Models; 2 | 3 | public class OrderDetail 4 | { 5 | public int Id { get; set; } 6 | public int Quantity { get; set; } 7 | public int ProductId { get; set; } 8 | public int OrderId { get; set; } 9 | 10 | public Order Order { get; set; } = null!; 11 | public Product Product { get; set; } = null!; 12 | } 13 | -------------------------------------------------------------------------------- /notes/1-getting-started/Product.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace ContosoPizza.Models; 5 | 6 | public class Product 7 | { 8 | public int Id { get; set; } 9 | 10 | public string Name { get; set; } = null!; 11 | 12 | [Column(TypeName = "decimal(6, 2)")] 13 | public decimal Price { get; set; } 14 | } -------------------------------------------------------------------------------- /notes/1-getting-started/Program-snippets.cs: -------------------------------------------------------------------------------- 1 | 2 | #region addProducts 3 | 4 | using ContosoPizza.Data; 5 | using ContosoPizza.Models; 6 | 7 | using ContosoPizzaContext context = new ContosoPizzaContext(); 8 | 9 | Product veggieSpecial = new Product() 10 | { 11 | Name = "Veggie Special Pizza", 12 | Price = 9.99M 13 | }; 14 | context.Products.Add(veggieSpecial); 15 | 16 | Product deluxeMeat = new Product() 17 | { 18 | Name = "Deluxe Meat Pizza", 19 | Price = 12.99M 20 | }; 21 | context.Add(deluxeMeat); 22 | 23 | context.SaveChanges(); 24 | 25 | #endregion 26 | 27 | #region displayProducts 28 | 29 | var products = context.Products 30 | .Where(p => p.Price > 10.00M) 31 | .OrderBy(p => p.Name); 32 | 33 | 34 | foreach (Product p in products) 35 | { 36 | Console.WriteLine($"Id: {p.Id}"); 37 | Console.WriteLine($"Name: {p.Name}"); 38 | Console.WriteLine($"Price: {p.Price}"); 39 | Console.WriteLine(new string('-', 20)); 40 | } 41 | 42 | #endregion 43 | 44 | #region linqProduct 45 | 46 | var products = from product in context.Products 47 | where product.Price > 10.00M 48 | orderby product.Name 49 | select product; 50 | 51 | #endregion 52 | 53 | #region updateProduct 54 | 55 | var veggieSpecial = context.Products 56 | .Where(p => p.Name == "Veggie Special Pizza") 57 | .FirstOrDefault(); 58 | 59 | if (veggieSpecial is Product) 60 | { 61 | veggieSpecial.Price = 10.99M; 62 | } 63 | 64 | context.SaveChanges(); 65 | 66 | #endregion -------------------------------------------------------------------------------- /notes/1-getting-started/connection-strings.md: -------------------------------------------------------------------------------- 1 | # Connection strings for Part 1 2 | 3 | ## If you are using SQL Server Express LocalDB 4 | 5 | ```text 6 | Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=ContosoPizza-Part1;Integrated Security=True; 7 | ``` 8 | 9 | ## If you are using SQL Server in the dev container 10 | 11 | ```text 12 | Data Source=localhost;Database=ContosoPizza-Part1;Integrated Security=false;User ID=sa;Password=P@ssw0rd; 13 | ``` 14 | -------------------------------------------------------------------------------- /notes/1-getting-started/entity-diagram.md: -------------------------------------------------------------------------------- 1 | # ContosoPizza Entity Diagram 2 | 3 | ```mermaid 4 | erDiagram 5 | Customer ||--o{ Order : places 6 | Order ||--|{ OrderDetail : contains 7 | Product }|--|{ OrderDetail : "ordered in" 8 | Customer { 9 | int Id 10 | string FirstName 11 | string LastName 12 | string Address 13 | string Phone 14 | string Email 15 | } 16 | Order { 17 | int Id 18 | timestamp OrderPlaced 19 | timestamp OrderFulfilled 20 | int CustomerId 21 | } 22 | OrderDetail { 23 | int Id 24 | int Quantity 25 | int OrderId 26 | int ProductId 27 | } 28 | Product { 29 | int Id 30 | string Name 31 | decimal Price 32 | } 33 | ``` 34 | -------------------------------------------------------------------------------- /notes/1-getting-started/script.md: -------------------------------------------------------------------------------- 1 | # Part 1 Script 2 | 3 | ## Please note: This is the working script used for shooting. The final videos may contain variations and adjustments. 4 | 5 | > Hi friends! I'm Cam Soper, a Content Developer working with .NET here at Microsoft. 6 | > 7 | > In this video, we're going to get started with Entity Framework Core, which is a toolset that makes it easy to store your .NET objects in a variety of databases without writing much (or any) database code. EF Core allows you to use a variety of databases, such as SQL Server, SQLite, Cosmos DB, and Postgres, just to name a few. 8 | 9 | Here's an entity diagram describing the entities we're going to persist to our database. These entities support a pizza delivery website, ContosoPizza. As you can see, a Customer can place one or more Orders. Each Order contains 1 or more OrderDetails, and each OrderDetail contains a Product and quantity. 10 | 11 | > Let's dive in! 12 | 13 | I'm starting with an empty .NET 6 console project. I'll manage my NuGet packages for the project, and search for `Microsoft.EntityFrameworkCore`. 14 | 15 | I'll grab the `Microsoft.EntityFrameworkCore.SqlServer` package and install it to my project. Now that that's installed, I'm also going to install `Microsoft.EntityFrameworkCore.Design` and `Microsoft.EntityFrameworkCore.Tools`. 16 | 17 | To get started with Entity Framework Core, we need to build classes describing our entity model. By convention, these are usually stored in a folder called models. 18 | 19 | I'm going to create the first entity, probably the simplest one, `Product`. We've added an empty class, and for expediency I'm going paste in some code. 20 | 21 | Looking at the `Product` class, the first thing that I want to call out is this first property, `Id`. In EF Core, `Id` is a special property name that indicates that this property is to be the primary key in the generated table. It doesn't have to be named `Id`, it can be the table name followed by `Id`, or it can be anything we want it to be, in which case we decorate the property with the `Key` attribute to indicate that it's a primary key. 22 | 23 | The other two properties on this class are `Name` and `Price`. We've attributes to define `Price` as a decimal with two points of precision. 24 | 25 | You may be wondering why I've initialized `Name` as null with an exclamation point. That's because in .NET 6, all projects enable nullable reference types by default. Without this initialization, the compiler warns us that it can't see where the non-nullable string NAME is initialized. EF Core manages entity intialization for us, so I suppressed the warning by explicitly initializing the property as null with the null-forgiving operator. This lets the compiler know we know what we're doing, so it doesn't need to warn us about this assignment. 26 | 27 | If you need to use a nullable reference type in your model, but you don't want nulls stored in the database, you can use the REQUIRED attribute. That's not the case here, so I'll revert this to the way I had it originally. 28 | 29 | The next class we're going to add will be the customer class. Here we're using nullable and non-nullable reference types to define which database fields should allow nulls and which ones shouldn't. Since FIRSTNAME and LASTNAME are non-nullable strings, EF Core knows that when it creates the table, those two columns should not allow nulls. 30 | 31 | The ADDRESS and PHONE properties, on the other hand, are nullable strings, so the database will allow nulls in those columns. We don't need to initialize these because they are declared as nullable. 32 | 33 | Finally, the last property on the class, called ORDERS, is a collection of ORDER objects. We haven't created the order class yet, we're going to do that in just a second. This is called a navigation property, and it indicates that a customer may have zero or more orders. This creates a one-to-many relationship in the database that gets generated. 34 | 35 | Creating the empty Order class, I'll again paste in some code to define my properties. This should look pretty familiar. We have an ID property, along with ORDERPLACED and ORDERFULFILLED properties. 36 | 37 | We also have a CUSTOMER property which is another type of navigation property, specifying one customer entity per order. We've included a Customer ID property to represent the foreign key relationship to the Customer table that will be generated. If we omit the customer ID property, that's okay, too. EF Core would create it anyway as a shadow property. 38 | 39 | Finally, we have another navigation property for a collection of OrderDetails, the final class we're going to create. 40 | 41 | Let's look at OrderDetail. This entity will generate an intersection table to facilitate the many-to-many relationship. It has navigation properties for both order and product. As with the Order class, the OrderId and ProductId represent foreign key relationships and aren't strictly required. 42 | 43 | Now we're going to create a database context class. By convention, this typically goes in a folder called "data." I'm going to name my class `ContosoPizzaContext`. 44 | 45 | `ContosoPizzaContext` derives from `DbContext`. Think of `DbContext` as representing a session with the database. On the `DbContext` derived class, we have four properties of type DBSet. Each DBSet maps to a table that will be created in the database. 46 | 47 | Finally, we've overridden the OnConfiguring method to include some configuration information. Since we're using the SQL Server package, we have a `UseSQLServer` extension method available to us that configures the SQL Server database provider. You can find the connection string in the notes for part 1. Set the connection string to the correct connection string for your environment. Hard-coding a connection string like this is a bad practice, and I'm just doing it for demonstration purposes. Always use a secure storage method for your real-world connection strings. 48 | 49 | So now that we've created our entity model, we're going to create something called a migration. The EF Core migrations feature is a tool that makes it easy to create and evolve our database. 50 | 51 | Since I'm using Visual Studio, I'm going to use the Package Manager Console to run the Add-Migration commandlet. I'll name my migration `InitialCreate`. 52 | 53 | If you're not using Visual Studio, you can do these same tasks using the .NET CLI. First install the dotnet-ef tool as a global tool. Then use the `dotnet ef migrations add` command to create the `InitialCreate` migration. 54 | 55 | Going back to Visual Studio, let's take a look at the generated migration. We should look it over to make sure it's accurate and it creates the table the way we want it to be created. 56 | 57 | Looking at the products table as an example, we can see where it's creating our identity column, our primary key, our Name (which is not nullable), and our price, which is a decimal with two points of precision. 58 | 59 | I'm satisfied that the migration is correct, so I'll run the migration with Visual Studio's `Update-Database` commandlet. The equivilent .NET CLI command is `dotnet ef database update`. 60 | 61 | Now let's take a look at the database that was created. 62 | 63 | The first table we're going to look at is this one that we didn't create at all, EF Migration History. This table is used by EF Core to track which migrations have been run against this database. 64 | 65 | Let's look at the products table. It looks like the products table was generated exactly as we intended. 66 | 67 | Let's also look at customer. The customer table was also generated pretty much as we expected, except I just realized that we need to store customer e-mail addresses. Let's go back to the customer entity and add a property for e-mail. E-mail will be a nullable string. 68 | 69 | Now that we've modified the customer entity, we'll create another migration. I'll name this one AddEmail. This migration will handle adding the new column. Let's go ahead and update the database again to make sure that our database is up-to-date with our migrations. As expected, the e-mail column has been added to the table. 70 | 71 | Now that we've built our database context and our entity model, let's go to *Program.cs* and do something with it. 72 | 73 | To get started, I'm going to add a few products to my products table. 74 | 75 | The first thing I'm going to do is use a Using declaration to create a new instance of ContosoPizzaContext. This Using declaration ensures that the ContosoPizzaContext object is disposed of properly when we're done using it. 76 | 77 | The first product I'm going to add to my table will be a Veggie Special Pizza. I create the veggieSpecial object and then call the Add method on Products DBSet property. 78 | 79 | The next product I'm going to add will be a Deluxe Meat Pizza. This time I call the add method from the context object. EF Core can infer that this entity is a Product based on its type. 80 | 81 | Finally, we're going to call the SaveChanges method on the context to persist the changes to the database. 82 | 83 | Let's run it and see what happens. In Visual Studio, you can use the Start Debugging button. If you're using the CLI, run the app with `dotnet run`. 84 | 85 | The app's done running. Let's look at the database. 86 | 87 | As expected, two products have been added to the products table; our Veggie Special Pizza and our Deluxe Meat Pizza. 88 | 89 | Now that there are some entities in the database, let's try reading them. Using that same ContosoPizzaContext reference, I'm going to query the products table using a Fluent API. Fluent APIs use extension methods to chain methods together, along with lambda expressions to specify the query. In this case, we're looking for any product where the price is greater than 10, and we're going to order by name. Then we're just going to write it all out to the console. 90 | 91 | If you don't like the Fluent API syntax, you can instead use the LINQ syntax. LINQ syntax is very similar to SQL code. Let's replace the fluent API syntax with the LINQ syntax. Both of these methods are equivalent and result in the same queries to the database. 92 | 93 | Let's run it. 94 | 95 | As expected, our one product whose price is greater than 10 shows up in the results. 96 | 97 | Now that we've read entities from the database, let's try updating an entity. To update an entity, first we have to get a reference to it. We'll query the table looking for any product whose name is Veggie Special Pizza and take the first or default result. If there's no record that matches that name, we'll get the default, which is null. Here we check to see if the veggieSpecial object is a Product object and not null, and if it is a Product object, we'll set the price to 10.99. Finally, we'll save our changes. 98 | 99 | Let's run it again. 100 | 101 | Since we changed the price to greater than 10, Veggie Special Pizza shows up in the result set now. 102 | 103 | The final thing I'm going to show is how to delete an entity from the database. To delete, you simply pass a reference to the entity to the remove function on the database context. 104 | 105 | Let's run one last time. 106 | 107 | As expected, Veggie Special Pizza is now deleted! 108 | 109 | > That's how easy it is to use Entity Framework Core to persist .NET objects in a database! In this video, we used EF Core migrations to create a new database from our code. In the next video, I'm going to show you how to go the other way, scaffolding code from an existing database. 110 | -------------------------------------------------------------------------------- /notes/2-existing-databases/Customer.cs: -------------------------------------------------------------------------------- 1 | namespace ContosoPizza.Models; 2 | 3 | public partial class Customer 4 | { 5 | public string FirstLast 6 | { 7 | get => $"{FirstName} {LastName}"; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /notes/2-existing-databases/Program.cs: -------------------------------------------------------------------------------- 1 | using ContosoPizza.Data; 2 | using ContosoPizza.Models; 3 | 4 | using ContosoPizzaContext context = new ContosoPizzaContext(); 5 | 6 | foreach (Customer c in context.Customers) 7 | { 8 | Console.WriteLine($"Name: {c.FirstLast}"); 9 | } -------------------------------------------------------------------------------- /notes/2-existing-databases/connection-strings-and-notes.md: -------------------------------------------------------------------------------- 1 | # Connection strings and notes for Part 2 2 | 3 | ## If you are using SQL Server Express LocalDB on Windows 4 | 5 | Connection string: 6 | 7 | ```text 8 | Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=ContosoPizza;Integrated Security=True; 9 | ``` 10 | 11 | The full `Scaffold-DbContext` command is: 12 | 13 | ```powershell 14 | Scaffold-DbContext "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=ContosoPizza;Integrated Security=True;" Microsoft.EntityFrameworkCore.SqlServer -ContextDir Data -OutputDir Models 15 | ``` 16 | 17 | ## If you are using SQL Server in the dev container 18 | 19 | Connection string: 20 | 21 | ```text 22 | Data Source=localhost;Database=ContosoPizza;Integrated Security=false;User ID=sa;Password=P@ssw0rd; 23 | ``` 24 | 25 | ## Scaffolding with `dotnet ef` 26 | 27 | To scaffold with `dotnet ef`, run: 28 | 29 | ```dotnet-cli 30 | dotnet add package Microsoft.EntityFrameworkCore.SqlServer 31 | dotnet add package Microsoft.EntityFrameworkCore.Tools 32 | dotnet add package Microsoft.EntityFrameworkCore.Design 33 | dotnet ef dbcontext scaffold "Connection String Here" Microsoft.EntityFrameworkCore.SqlServer --context-dir Data --output-dir Models 34 | ``` 35 | 36 | The other parameters you'll need are: 37 | 38 | - `--data-annotations` 39 | - `--namespace` (for model namespace) 40 | - `--context-namespace` (for DbContext namespace) 41 | -------------------------------------------------------------------------------- /notes/2-existing-databases/script.md: -------------------------------------------------------------------------------- 1 | # Part 2 Script 2 | 3 | ## Please note: This is the working script used for shooting. The final videos may contain variations and adjustments. 4 | 5 | > Hi, friends! Welcome back to Entity Framework Core for Beginners. 6 | > 7 | > In our previous video, I showed you how easy it is to use Entity Framework Core migrations to create and work with a new database. First, we defined our entity model in code. Then we used migrations to change the database as we made changes to the model. When we use that approach, we're treating the code as the authoritative "source of truth" regarding the shape of our entities. 8 | > 9 | > In this video, I'm going to show you how to use Entity Framework Core to work with an existing database by reverse engineering it. This approach treats the database as the source of truth. 10 | 11 | Looking at Visual Studio, I have a brand new console app that doesn't have any code added to it at all. I've already added the Microsoft.EntityFrameworkCore.SqlServer, .Design, and .Tools NuGet packages. 12 | 13 | I have an existing database. Let's assume was created and maintained by my organization's Database Administrator. This database is already populated. 14 | 15 | To reverse engineer the database and create my entity model code, I'll start by using the Scaffold-DbContext commandlet. I'm going to pass in the connection string (which can be found in the notes). I'm going to pass in the name of the provider so it knows what type of database to execute the connection string on, and then I'm going to optionally specify output directories for the dbcontext and models. 16 | 17 | If you're using the .NET CLI, the command is `dotnet ef dbcontext scaffold`. The parameters are similar. 18 | 19 | Now that the Scaffold is run, we have a complete working entity model. 20 | 21 | Looking at the product entity, it should look pretty similar to the one we created in the last video. One difference you'll note, however, is there are no data annotations describing the behavior of these properties, like the one we used previously for `Price`. 22 | 23 | That's because these behaviors are contained in the OnModelCreating method of the database context. This is another way EF Core lets you control the relationship between your entities and the database. 24 | 25 | If we'd like to generate an entity model that looks more like the one we created in the previous video, we can do that too. I'll start by deleting this entity model, and I'll run the Scaffold-DbContext command again. This time, I'll add the data annotation flag. 26 | 27 | Now the product entity has data attributes that describe the behavior of the properties. The OnModelCreating method in the database context is also much more sparse. 28 | 29 | > You might be wondering, what do we do when the database schema changes? There are two strategies. 30 | > 31 | > The first strategy is a manual approach. This approach requires you to manually edit your entity model to keep in sync with the database schema. The generated dbcontext and models can thought of as a starting point for ongoing development, similar to scaffolded razor pages in ASP.NET Core. 32 | > 33 | > The other strategy is rescaffolding the entity model whenever the database schema changes. Using this approach, it's important to use partial classes or extension methods to keep business logic separate from scaffolded entities. This ensures that business logic doesn't get overwritten if you re-scaffold the entities. Let's take a look. 34 | 35 | I'm going to delete my entity model and re-scaffold. This time, I'm going to generate the models in a subdirectory of the Models directory, I'll specify the namespaces for the generated classes. 36 | 37 | Now I can create partial classes in the Models directory to contain my business logic. This way, I can regenerate the entity models without disturbing my business logic. 38 | 39 | Let's paste some code into *Program.cs* so we can see the partial class in action. 40 | 41 | > Now that we've seen how Entity Framework Core can work with an existing database, in the next video, I'm going to show you how to use Entity Framework Core with ASP.NET Core to streamline your web development. 42 | -------------------------------------------------------------------------------- /notes/3-web-sites/notes-and-snippets.md: -------------------------------------------------------------------------------- 1 | # Notes and snippets for part 3 2 | 3 | ## Program.cs snippet 4 | 5 | ```csharp 6 | builder.Services.AddDbContext(options => 7 | options.UseSqlServer(builder.Configuration.GetConnectionString("ContosoPizza"))); 8 | ``` 9 | 10 | ## Connection Strings 11 | 12 | ### SQL Server Express LocalDB 13 | 14 | ```text 15 | Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=ContosoPizza;Integrated Security=True; 16 | ``` 17 | 18 | ### Dev Container 19 | 20 | ```text 21 | Data Source=localhost;Database=ContosoPizza;Integrated Security=false;User ID=sa;Password=P@ssw0rd; 22 | ``` 23 | 24 | ## User Secrets 25 | 26 | ### secrets.json 27 | 28 | > **Important!**: Be sure any `\` characters are properly escaped for JSON encoding (e.g., `\` in the connection string is `\\` in *secrets.json*)! 29 | 30 | ```json 31 | { 32 | "ConnectionStrings:ContosoPizza": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=ContosoPizza;Integrated Security=True;" 33 | } 34 | ``` 35 | 36 | ### `dotnet` commands 37 | 38 | ```dotnet-cli 39 | dotnet user-secrets init 40 | dotnet user-secrets set "ConnectionStrings:ContosoPizza" "Connection String Here" 41 | ``` 42 | 43 | ## Scaffolding with `dotnet` 44 | 45 | ```dotnet-cli 46 | dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design 47 | dotnet tool install -g dotnet-aspnet-codegenerator 48 | dotnet aspnet-codegenerator razorpage --model Product --dataContext ContosoPizzaContext --relativeFolderPath Pages/Products --referenceScriptLibraries 49 | ``` 50 | 51 | dotnet user-secrets set "ConnectionStrings:ContosoPizza" "Data Source=localhost;Database=ContosoPizza;Integrated Security=false;User ID=sa;Password=P@ssw0rd;" 52 | -------------------------------------------------------------------------------- /notes/3-web-sites/script.md: -------------------------------------------------------------------------------- 1 | # Part 3 Script 2 | 3 | ## Please note: This is the working script used for shooting. The final videos may contain variations and adjustments. 4 | 5 | > Hi, friends! Welcome back to Entity Framework Core for Beginners. 6 | > 7 | > In this video, I'm going to show you how you can use Entity Framework Core with ASP.NET Core scaffolding to streamline your web development. Let's get to it! 8 | 9 | I've already created an empty ASP.NET Core Razor Pages web app. I used the command I showed you in the last video to scaffold a `DbContext` and models against that same database. Now we're going to scaffold some Razor pages that use `ContosoPizzaContext` to interact with the database. 10 | 11 | `ContosoPizzaContext` contains the connection string that was used for scaffold in the `OnConfiguring` method. We're going to get our connection information from configuration, so let's delete that method. 12 | 13 | Now I'm going to visit *Program.cs*. I'll paste in some code to and then I'll add the `using` directives to resolve those references. 14 | 15 | The `AddDbContext` extension method registers `ContosoPizzaContext` with ASP.NET Core's dependency injection container. We pass the method a lambda expression that configures EF Core to use the SQL Server database provider using a connection string retrieved from configuration. 16 | 17 | > In the previous videos, I've mentioned that it's a bad practice to store your connection strings with your code. The .NET Secrets Manager gives us a mechanism to separate our secrets from our code. Let's use the .NET secrets manager to store that connection string. 18 | 19 | I'm right-clicking on the project and selecting **Manage User Secrets**. Visual Studio opens a file named *secrets.json* for editing, and I'll paste in my connection string. This file is stored in you user profile on your development machine. The secrets aren't encrypted. It's just a location to store them away from your code. At runtime, ASP.NET Core will look for the configuration in *appsettings.json* and other locations. *secrets.json* is one of the locations it checks. 20 | 21 | If you're using the .NET CLI, you must first initialize the secret store with `dotnet user-secrets init`. Then you can add the your secrets with `dotnet user-secrets set`. 22 | 23 | Now we're going to generate razor pages to support Creating, Reading, Updating, and Deleting products. These operations are collectively referred to as CRUD. The first thing I'm going to do is add the `Microsoft.VisualStudio.Web.CodeGeneration.Design` package to the project. This installs some dependencies for the scaffolding tool. 24 | 25 | Now I'll create a Products folder inside the Pages folder. After that, I'll right-click on the folder, select "Add", and then "New Scaffolded Item..." In the dialog that follows, select Razor Pages using Entity Framework CRUD. Select `Product` as the model class and `ContosoPizzaContext` as the data context class. Click Add. 26 | 27 | If you're using the .NET CLI, first install the `dotnet-aspnet-codegenerator` tool as a global tool. Then use the `dotnet aspnet-codegenerator` command to scaffold the pages. I've put the full command in the notes. 28 | 29 | The scaffolding creates five pages: Create, Delete, Details, Edit, and Index. 30 | 31 | I'm going to run the application. I'll edit my URL to navigate directly to the products Index page. This View lists all the products in the table. I'm going to leave the app running, but I'll switch back to my IDE. Let's look at the code for *Index.cshtml.cs*. 32 | 33 | Notice that we're injecting `ContosoPizzaContext` into the constructor. ASP.NET Core's dependency injection container takes care of this for us. All we have to do is ensure the constructor has the right signature. 34 | 35 | The products collection is accessed by a property on the page model class. The `OnGet` method sets that property equal to the contents of the `Products` `DbSet`. 36 | 37 | The Razor view enumerates over that list of products and for each product lists the name and price. 38 | 39 | Let's use the Create page to create a new product. 40 | 41 | There's a new product. Let's look at what happened in the code. We'll start with the page model. The `OnGet` method in the page model returns the empty form, which is a Razor view. 42 | 43 | The Razor view has elements to support name and price. It uses label, input, and span elements to build the form that we saw earlier. This includes validation that enforces the constraints in our model classes. 44 | 45 | When we post the form, the model binder binds the elements on the form to our product property, which in turn is added to the products `DbSet`. Finally, we call `SaveChangesAsync` to save the changes to the database. 46 | 47 | Let's edit a record. When we visit this page, the name and price elements are pre-populated with existing data. Looking at the page model for `Edit`, the `OnGet` method queries the database for products that match the `Id` that was passed in on the URL's query string. We retrieve that product and present it for the user to edit. 48 | 49 | When the user posts the form, the model binder builds a `Product` object from the elements on the page, attaches it to the existing entity, marks it as modified, and saves the changes. 50 | 51 | The final view we're going to look at is `Delete`. The `Delete` view is similar to the `Edit` view. The first thing `OnGet` does is look up the product by `Id` and display it for the user. 52 | 53 | When the user clicks the "Submit" button, we find that same product by its ID. Then we call `Remove` on the `Products` `DbSet`, passing in the entity to delete. 54 | 55 | > In this video, we saw how easy it is to use ASP.NET Core along with Entity Framework Core to streamline your web development. In the next video, we're going to look at using different database providers with Entity Framework Core. 56 | -------------------------------------------------------------------------------- /notes/4-database-providers/connection-strings-and-notes.md: -------------------------------------------------------------------------------- 1 | # Connection strings and notes for Part 4 2 | 3 | ### ContosoPizza.csproj snippet 4 | 5 | ```xml 6 | $(MSBuildProjectDirectory) 7 | ``` 8 | 9 | ## Postgres in the dev container 10 | 11 | Connection string: 12 | 13 | ```text 14 | User ID=postgres;Password=P@ssw0rd;Host=localhost;Port=5432;Database=ContosoPizza; 15 | ``` 16 | 17 | SELECT: 18 | 19 | ```sql 20 | SELECT * FROM "Products" 21 | ``` 22 | 23 | ## Azure Cosmos DB 24 | 25 | You can use an actual Cosmos DB account in the cloud, or you can use the local emulator. 26 | 27 | - [Quickstart: Create an Azure Cosmos account, database, container, and items from the Azure portal](https://docs.microsoft.com/azure/cosmos-db/sql/create-cosmosdb-resources-portal) 28 | - [Azure Cosmos DB local emulator](https://docs.microsoft.com/azure/cosmos-db/local-emulator) 29 | - [Free Azure Account](https://azure.microsoft.com/free/dotnet/) 30 | -------------------------------------------------------------------------------- /notes/4-database-providers/script.md: -------------------------------------------------------------------------------- 1 | # Part 4 Script 2 | 3 | ## Please note: This is the working script used for shooting. The final videos may contain variations and adjustments. 4 | 5 | > Hi, friends! Welcome back to Entity Framework Core for Beginners. 6 | > 7 | > In previous videos, we've looked at using Entity Framework Core exclusively with SQL Server. In this video, we're going to look at using Entity Framework Core with other database providers. 8 | 9 | The database provider is a layer in the EF Core architecture that's responsible for the communication between Entity Framework Core and the database. It's a pluggable architecture, which means EF Core can support all kinds of databases. 10 | 11 | > The first database provider we're going to look at is Sqlite. Sqlite is an open-source cross-platform embedded database technology. In Sqlite, the entire database is stored in a single file, so it's a great choice when you don't want to take a dependency on a server-based database platform. 12 | 13 | I'm starting with a console application preconfigured with my NuGet packages. I've already written context and model classes. The code in *Program.cs* adds some records to the Products table. 14 | 15 | Using a different database provider with EF Core is often as simple as using a different NuGet package. To use the Sqlite provider, I'm going to install the `Microsoft.EntityFrameworkCore.Sqlite` package. I'll uninstall the SqlServer package, too. Then I'll go to the `OnConfiguring` method in `ContosoPizzaContext` and configure the context with the `UseSqlite` extension method. The connection string points to the file to be created. 16 | 17 | Now I'll create my InitialCreate migration. After that, I'll use `Update-Database` to run the migrations. The *ContosoPizza.db* file was created. 18 | 19 | Before we run, since I'm using Visual Studio, there's one other thing I need to check. By default, Visual Studio wants to start the app in a different directory than the build directory. If it does that, my app won't find the database. Let's add a `` element to the *.csproj* so that doesn't happen. Now let's run the app! 20 | 21 | It's done running. Let's see if we got data in our file. In Visual Studio, I'll right click and get the path of the file, which I'm going to use to open it in an open source tool called DB Browser. As you can see, the Product data looks as we expected. 22 | 23 | > Now let's do that same exercise again, but this time let's use Postgres. The database provider for Postgres is provided by the Postgres developer community. 24 | 25 | I'll add the `Npgsql.EntityFrameworkCore.PostgreSQL` package to the project and delete the Sqlite package. Now I'll replace the the call to the `.UseSqlite` method with a call to `.UseNpgsql`. 26 | 27 | Now I'll generate and run new migrations. 28 | 29 | Lets run the app. 30 | 31 | The app's done running. I'llm switch over to the pgAdmin tool and query the database. As you can see, the Product table has data. 32 | 33 | > The final database provider I'm going to show you is for Azure Cosmos DB. Cosmos DB is a fully managed NoSQL database for modern app development. This means that instead of working like a relational database management system, it works with JSON documents. 34 | 35 | I've already created a free Cosmos DB account configured to use the Core API. I haven't added any database containers yet. It's just an empty Cosmos account. 36 | 37 | I'll go to the Keys tab to get my connection string, then I'll go back to Visual Studio. 38 | 39 | I'll add the `Microsoft.EntityFrameworkCore.Cosmos` package to the project and remove the Postgres package. This time I'll call the `.UseCosmos` method. In addition to the connection string, I must also specify a database name. 40 | 41 | Since Cosmos DB is a NoSQL database, and there aren't any database schemas to update, let's delete the Migrations folder. 42 | 43 | Since there are no migrations to create the initial database, let's call `context.Database.EnsureCreated` in *Program.cs* to make sure the database gets created. `EnsureCreated` can cause performance issues, so avoid using it in production. 44 | 45 | One other difference we need to account for with Cosmos DB is with the primary keys. The other databases we used support auto-generating a primary identifier. Since Cosmos DB doesn't do that, we need to handle it ourselves. 46 | 47 | I'll change the Product entity model so that `Id` is a string. I'll initialize it to a new globally unique identifier. Since this primary key is a foreign key on `OrderDetails`, I'll change `ProductID` to be a string as well, and I'll assign it to null along with the null-forgiving operator. 48 | 49 | Let's run the app. Now that that's done, we'll go over to the Azure portal, where we can see the data we just added. 50 | 51 | > In this video, we looked at how EF Core uses database providers to support a plethora of different database technologies. We looked at just three of the possible database providers you can use. Visit the Entity Framework Core documentation to see the full list of supported providers. 52 | > 53 | > In the next video, I'm going to show you some tips to optimize performance in your EF Core applications. -------------------------------------------------------------------------------- /notes/5-performance-tips/connection-strings-and-notes.md: -------------------------------------------------------------------------------- 1 | # Connection strings and notes for Part 5 2 | 3 | Make sure you add your connection string to Secrets Manager! See part 3 if you need a refresher. 4 | 5 | ## SQL query string for `FromSqlInterpolated` 6 | 7 | ```csharp 8 | $"SELECT * FROM Customers WHERE Id = {CustomerId}" 9 | ``` -------------------------------------------------------------------------------- /notes/5-performance-tips/script.md: -------------------------------------------------------------------------------- 1 | # Part 5 Script 2 | 3 | ## Please note: This is the working script used for shooting. The final videos may contain variations and adjustments. 4 | 5 | > Hi, friends! Welcome back to Entity Framework Core for Beginners. In this video, I'm going to show you some tips to get the most performance out of your EF Core applications. 6 | > 7 | > The first topic we're going to cover is change tracking. When EF Core queries a database, it stores a snapshot of the results set in memory. Any modifications you make to your entities are actually made against that snapshot, and then later written to the database. In read-only scenarios where there's no chance you'll actually want to write data back to the database, we can skip the snapshot and conserve system resources. Let's look at how to disable change tracking for a query. 8 | 9 | I've got my ContosoPizza web app open, and I've set up my user secrets already. I'm going to disable change tracking on my Customer Index page, since that page is read-only. To disable change tracking on any results set, all we have to do is add the `AsNoTracking` method to the query. Now when we view the Customer Index view, EF Core will skip the snapshot. 10 | 11 | > In our previous videos, we've looked at using navigation properties to load related entities. Entity Framework Core allows you to specify when those related entities are read from the database. We're going to look at two patterns for loading those entities: Eager loading and lazy loading. 12 | 13 | We'll look at eager loading first. Here's that same Customer Index page. We're already using eager loading by way of the `Include` method. The `Include` method signals to EF Core that the related orders should be loaded on the same database query as the customers. 14 | 15 | Sometimes, however, it might benefit our app's performance to wait to load the orders until they're actually needed. This is called lazy loading. To enable lazy loading, first I'm going to install the `Microsoft.EntityFrameworkCore.Proxies` package. I'm going to get rid of the `Include` method. `AsNoTracking` doesn't work with lazy loading, so I'll get rid of that too. 16 | 17 | When I add the database context to the dependency injection container, I'm going to add `UseLazyLoadingProxies` to the options. 18 | 19 | Finally, I'll go make sure the navigation properties are marked virtual so that Entity Framework Core can override them with the proxies that it generates. 20 | 21 | Now I've enabled lazy loading, and the orders won't be requested from the database until they're actually needed by our code. 22 | 23 | > When eager loading one-to-many datasets, EF Core defaults to using LEFT JOINs to get the entire dataset from the database in one query. This can lead to very large datasets when the data from the LEFT side of the JOIN is repeated for each record returned on the RIGHT side. This is known as a cartesian explosion, and it can be mitigated by using a feature called split queries. Split queries use multiple queries to get the same dataset. 24 | 25 | I'm already running the app. The Customer Details page needs to use a lot of navigation properties. The debugger output shows the query that's sent to SQL Server. You can see that it's using one big query. To use a split query, all I need to do is add the `AsSplitQuery` method. Now I'll hot-reload the page. This time, instead of a single SQL query, there are three. 26 | 27 | > Sometimes when working with Entity Framework Core, you need to use your own SQL rather than the SQL that it generates for you. Entity Framework Core makes this easy using the `FromSqlRaw` and `FromSqlInterpolated` methods. 28 | 29 | Let's look at the Product detail page. That page is currently loading Customer data using a `Where` method. I'm going to use `FromSqlInterpolated` to specify my own SQL query to retrieve some customer information from the database. I'll use an interperpolated string containing raw SQL and passing in Customer ID. 30 | 31 | Let's run it! After it launches, I'll drill down on a customer order to view a product. 32 | 33 | Entity Framework Core takes care of converting this interpolated string to a parameterized SQL statement, which protects from SQL injection attacks. 34 | 35 | > We've previously discussed how Entity Framework Core uses in-memory snapshots to track changes to our entities. If we happen to have an entity cached in the snapshot, we can save ourselves a trip to the database by looking it up with the `Find` or `FindAsync` methods. 36 | 37 | In my Products Details page, I'm using `FirstOrDefaultAsync` to look up a product from the database by its primary key. Since I'm looking up an entity by primary key, I can instead use `FindAsync`. This checks the snapshot first before calling the database. 38 | 39 | > Whenever we use a database context, there's a certain amount of overhead that goes into creating and destroying the object. We can bypass that overhead by using database context pooling to reuse our database context objects over and over again. 40 | 41 | To use database context pooling, all we have to do is replace `AddDbContext` use the `AddDbContextPool` method. Now, our database contexts will be reused over and over again. 42 | 43 | > This concludes Entity Framework Core for Beginners. Be sure to check out aka.ms/ef-core-101 for more great learning resources! 44 | > 45 | > Thanks for watching! 🙂 -------------------------------------------------------------------------------- /notes/series-outline.md: -------------------------------------------------------------------------------- 1 | # Entity Framework Core video series 2 | 3 | > Please note: This is a rough working outline for this series. It was used to create the scripts for each part, and was never updated to reflect the final scripts. It's included here for completeness and as an artifact to aid maintainers during future updates to the series. 4 | 5 | ## Part 1: Intro to EF Core (15 mins) 6 | 7 | 1. Intro 8 | 1. EF Core makes it easy to store your objects in a database without writing much, if any, database code. 9 | 1. It supports a lot of different database engines, like SQL Server, Postgres, and Azure Cosmos DB. 10 | 11 | 1. Walkthrough 12 | 1. File > New Project > Console App 13 | 1. Paste in location - C:\Src\ef-core-101\parts\1 - Getting Started 14 | 1. Add NuGet Packages (Manage NuGet Packages dialog) 15 | 1. `Microsoft.EntityFrameworkCore.SqlServer` 16 | 1. `Microsoft.EntityFrameworkCore.Design` 17 | 1. `Microsoft.EntityFrameworkCore.Tools` 18 | 1. Build the ContosoPets domain model 19 | 1. Explain that we're building [this database](https://docs.microsoft.com/en-us/learn/aspnetcore/persist-data-ef-core/media/4-design-domain-model/database-diagram.png) 20 | 1. *Product.cs* (product snippet) 21 | - `Id` is primary key (by convention - explain equivalent to `[Key]`) 22 | - `[Required]` attribute on Name property -- EF Core doesn't enforce validation! 23 | - `[Column]` attribute on Price property 24 | 1. *Customer.cs* (customer snippet) 25 | - `Orders` navigation property => One-to-many relationship 26 | 1. *Order.cs* (order snippet) 27 | - `ProductOrder` => navigation property 28 | 1. *ProductOrder.cs* (po snippet) 29 | - navigation properties => many-to-many, intersection table 30 | - `ProductId` and `OrderId` => shadow properties if not included 31 | 1. Create `ContosoPetsContext` (same gist) 32 | 1. `DbSet` 33 | 1. Mention why you shouldn't hard-code the connection string like we are. 34 | 1. Create and run the `InitialCreate` migration. (define migration as "set of tools to evolve db") Show new tables in SQL Server Object Explorer, ending with Customer 35 | 1. We forgot the `Email` property! Add it to *Customer.cs* and create and run the `AddEmail` migration. Show modified Customer table. 36 | 1. addproducts snippet in *Program.cs* to add a couple products. Build & run. Show new rows in SQL Server Object Explorer 37 | 1. displayproducts snippet in *Program.cs* to read a filtered, ordered list of products to console. 38 | 1. linqproducts snippet to change previous query to Linq format. Build & run. 39 | 1. updateproduct snippet in *Program.cs* to modify a single product (price increase). Build & run. P 40 | 1. Replace line that sets price with `context.Remove(veggieSpecial);` in *Program.cs* to delete a single product. Build & run. 41 | 42 | 1. Outro 43 | 1. Check out aka.ms/learn-ef-core! 44 | 45 | ## Part 2: Working with an Existing Database (10 min) 46 | 47 | 1. Intro 48 | 49 | Many developers want the features of EF Core, but have to use it with an existing database. EF Core provides tools to reverse-engineer an existing database and generate an entity model. 50 | 51 | 1. Walkthrough 52 | 1. Existing empty console application 53 | 1) NuGet packages are already in csproj 54 | 1. `Scaffold-DbContext` (paste full command from text file) 55 | 1. Walk through a generated class (customer?), point out attributes, compare to table designer view 56 | 57 | 1. Outro 58 | 59 | ## Part 3: ASP.NET Core web apps with EF Core (5-10 min) 60 | 61 | 1. Intro 62 | 63 | 1. Walkthrough 64 | 1. Start with brand new web app, start with Model and Database and everything ready to go 65 | 1. Register `DbContext` in DI Container. 66 | - Don't go too deep in the weeds on DI 67 | 1. Scaffold Razor pages (Razor Pages Using EF (CRUD)) 68 | 1. Define scaffolding (high level) 69 | 1. *Products/Index.cshtml* 70 | - `ContosoPetsContext` is injected into *Index.cshtml.cs* 71 | - The .cshtml loops over the entire collection. 72 | 1. Run the app. Browse to Products/Index. 73 | 1. Browse Products/Create 74 | 1. Show *Create.cshtml* and *Create.cshtml.cs*. 75 | - Validation tag helpers enforce the model's constraints. 76 | - `.OnPost() => .Add()`, `.SaveChanges()` 77 | 1. Browse Products/Index. Click Edit on a product. 78 | 1. Show *Edit.cshtml.cs* 79 | - `OnGet` finds the record indicated by the ID in the URL. 80 | - `OnPost` does the same, modifies it, and persists to database. 81 | 1. Browse back to Products/Index. Click **Delete** on a product. 82 | 1. Show *Delete.cshtml.cs* where the record is deleted 83 | 1. Click the Confirm button on the page. 84 | 85 | 1. Outro 86 | 87 | ## Part 4: Database Providers (< 5 min) 88 | 89 | 1. Intro 90 | 1. Mention something about how we've been using SQL Server so far, but EF Core supports lots of different databases 91 | 92 | 1. Walkthrough 93 | 1. Quickly talk through [this image](https://docs.microsoft.com/en-us/learn/aspnetcore/persist-data-ef-core/media/2-setup-environment/ef-core-architecture.png) and how it relates to DB Providers 94 | 1. SqlLite 95 | 1. Define SqLite (x-plat, small, fast, embedded) 96 | 1. Show working web app 97 | 1. Show package reference: `Microsoft.EntityFrameworkCore.Sqlite` 98 | 1. Show *Program.cs* where we call `context.Database.EnsureCreated()` 99 | 1. Run web app, add a new product 100 | 1. Show *ContosoPets.db* created 101 | 1. Show new product in Sqllite GUI tool DB Browser 102 | 1. Cosmos DB 103 | 1. Define Cosmos (cloud, distributed, resilient, NoSQL) 104 | 1. Show working web app 105 | 1. Show package reference: `Microsoft.EntityFrameworkCore.Cosmos` 106 | 1. Show Program.cs where we call `context.Database.EnsureCreated()` 107 | 1. Show in Product.cs where Id is a string (not int) and setting default value to NewGuid() 108 | 1. Run web app, add a new product 109 | 1. Show new product in Azure Portal 110 | 1. Mention 3rd party DB providers, show [providers doc](https://docs.microsoft.com/en-us/ef/core/providers/?tabs=dotnet-core-cli) 111 | 112 | 1. Outro 113 | 114 | ## Part 5: EF Core Performance Tips (5 minutes) 115 | 116 | 1. Intro 117 | 118 | 1. Walkthrough 119 | 1. [No-tracking Queries](https://docs.microsoft.com/ef/core/querying/tracking#no-tracking-queries) 120 | 1. Explain change tracking (tracking a snapshot). 121 | - Don't need resources to track large result sets 122 | 1. `.AsNoTracking()` on *Products\Details.cshtml.cs* 123 | 1. [Loading related entities](https://docs.microsoft.com/ef/core/querying/related-data) 124 | 1. *Customer\Details.cshtml* 125 | 1. `.FromSqlInterpolated()` 126 | 1) fromsql snippet - Replace query in *Products\Index.cshtml.cs* to filter results 127 | 1. `.FindAsync()` 128 | 1) Only goes to the database if a snapshot of the entity doesn't exist in memory 129 | 2) Show in *Products\Details.cshtml.cs* 130 | 1. `DbContext` Pooling - *Startup.cs* 131 | 132 | 1. Outro 133 | -------------------------------------------------------------------------------- /notes/supplemental/script.md: -------------------------------------------------------------------------------- 1 | # Supplemental Part Script 2 | 3 | ## Please note: This is the working script used for shooting. The final videos may contain variations and adjustments. 4 | 5 | > Hi, friends! I'm Cam Soper, a content developer working with .NET at Microsoft. I wanted to take a few minutes to show you my recommendations on how to get the most from this video series. 6 | 7 | Before you get started, you should obtain the code, sample data, and notes for this series. They're located on GitHub at the location shown here. 8 | 9 | In the videos, I primarily use Visual Studio. This is a great option if you're a Windows user. If you're using Visual Studio, make sure you have the ASP.NET and web development workload installed. 10 | 11 | If you're developing on Windows, you'll also need a SQL Server Express LocalDB instance. A DACPAC file is located in the .devcontainer folder in the data subfolder. Use a tool like Azure Data Studio or SQL Server Management Studio to installs the database and name it ContosoPizza. 12 | 13 | To follow along in Visual Studio open the Project file for the part you're viewing directly in Visual Studio. 14 | 15 | If you're on a non-Windows environment or you just prefer a different IDE, you can use the .NET CLI and your IDE of choice. I recommend Visual Studio Code. Open the entire repository folder. 16 | 17 | I used the CodeTour extension in VS Code to make tours that walk you through the code interactively. If you have the CodeTour extension installed, you can launch the CodeTour for each video part by right-clicking and starting the tour you want in the CodeTour pane in the explorer. 18 | 19 | My favorite way to experience these videos is with a dev container. If you have a container environment configured, you can load the repository folder using Visual Studio Code's Remote Developement - Containers extension. Visual Studio Code will build a container environment pre-configured with specific versions of the .NET SDK, SQL Server, Postgres, and other tools, as well the pre-existing SQL Server database. You don't even need to install any extensions. There's nothing for you to do except launch the CodeTour. 20 | 21 | Finally, if your organization has access to GitHub Codespaces, you can launch the dev container in the cloud without any local tools. Just navigate to the code repository, click the **Code** button, and create a new Codespace using the `main` branch. 22 | 23 | > Thank you for watching these videos. I hope you find them informative, and I hope you have as much fun learning from them as I did making them. 24 | -------------------------------------------------------------------------------- /parts/1-getting-started/ContosoPizza/ContosoPizza.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /parts/1-getting-started/ContosoPizza/Program.cs: -------------------------------------------------------------------------------- 1 | // See https://aka.ms/new-console-template for more information 2 | Console.WriteLine("Hello, World!"); 3 | -------------------------------------------------------------------------------- /parts/2-existing-databases/ContosoPizza/ContosoPizza.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | all 13 | runtime; build; native; contentfiles; analyzers; buildtransitive 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /parts/2-existing-databases/ContosoPizza/Program.cs: -------------------------------------------------------------------------------- 1 | // See https://aka.ms/new-console-template for more information 2 | Console.WriteLine("Hello, World!"); 3 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/ContosoPizza.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | runtime; build; native; contentfiles; analyzers; buildtransitive 12 | all 13 | 14 | 15 | 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | all 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/Data/ContosoPizzaContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | using ContosoPizza.Models; 6 | 7 | namespace ContosoPizza.Data 8 | { 9 | public partial class ContosoPizzaContext : DbContext 10 | { 11 | public ContosoPizzaContext() 12 | { 13 | } 14 | 15 | public ContosoPizzaContext(DbContextOptions options) 16 | : base(options) 17 | { 18 | } 19 | 20 | public virtual DbSet Customers { get; set; } = null!; 21 | public virtual DbSet Orders { get; set; } = null!; 22 | public virtual DbSet OrderDetails { get; set; } = null!; 23 | public virtual DbSet Products { get; set; } = null!; 24 | 25 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 26 | { 27 | if (!optionsBuilder.IsConfigured) 28 | { 29 | #warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see http://go.microsoft.com/fwlink/?LinkId=723263. 30 | optionsBuilder.UseSqlServer("Data Source=localhost;Database=ContosoPizza;Integrated Security=false;User ID=sa;Password=P@ssw0rd;"); 31 | } 32 | } 33 | 34 | protected override void OnModelCreating(ModelBuilder modelBuilder) 35 | { 36 | modelBuilder.Entity(entity => 37 | { 38 | entity.HasIndex(e => e.CustomerId, "IX_Orders_CustomerId"); 39 | 40 | entity.HasOne(d => d.Customer) 41 | .WithMany(p => p.Orders) 42 | .HasForeignKey(d => d.CustomerId); 43 | }); 44 | 45 | modelBuilder.Entity(entity => 46 | { 47 | entity.HasIndex(e => e.OrderId, "IX_OrderDetails_OrderId"); 48 | 49 | entity.HasIndex(e => e.ProductId, "IX_OrderDetails_ProductId"); 50 | 51 | entity.HasOne(d => d.Order) 52 | .WithMany(p => p.OrderDetails) 53 | .HasForeignKey(d => d.OrderId); 54 | 55 | entity.HasOne(d => d.Product) 56 | .WithMany(p => p.OrderDetails) 57 | .HasForeignKey(d => d.ProductId); 58 | }); 59 | 60 | modelBuilder.Entity(entity => 61 | { 62 | entity.Property(e => e.Price).HasColumnType("decimal(6, 2)"); 63 | }); 64 | 65 | OnModelCreatingPartial(modelBuilder); 66 | } 67 | 68 | partial void OnModelCreatingPartial(ModelBuilder modelBuilder); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/Models/Customer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ContosoPizza.Models 5 | { 6 | public partial class Customer 7 | { 8 | public Customer() 9 | { 10 | Orders = new HashSet(); 11 | } 12 | 13 | public int Id { get; set; } 14 | public string FirstName { get; set; } = null!; 15 | public string LastName { get; set; } = null!; 16 | public string? Address { get; set; } 17 | public string? Phone { get; set; } 18 | public string? Email { get; set; } 19 | 20 | public virtual ICollection Orders { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/Models/Order.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ContosoPizza.Models 5 | { 6 | public partial class Order 7 | { 8 | public Order() 9 | { 10 | OrderDetails = new HashSet(); 11 | } 12 | 13 | public int Id { get; set; } 14 | public DateTime OrderPlaced { get; set; } 15 | public DateTime? OrderFulfilled { get; set; } 16 | public int CustomerId { get; set; } 17 | 18 | public virtual Customer Customer { get; set; } = null!; 19 | public virtual ICollection OrderDetails { get; set; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/Models/OrderDetail.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ContosoPizza.Models 5 | { 6 | public partial class OrderDetail 7 | { 8 | public int Id { get; set; } 9 | public int Quantity { get; set; } 10 | public int ProductId { get; set; } 11 | public int OrderId { get; set; } 12 | 13 | public virtual Order Order { get; set; } = null!; 14 | public virtual Product Product { get; set; } = null!; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/Models/Product.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ContosoPizza.Models 5 | { 6 | public partial class Product 7 | { 8 | public Product() 9 | { 10 | OrderDetails = new HashSet(); 11 | } 12 | 13 | public int Id { get; set; } 14 | public string Name { get; set; } = null!; 15 | public decimal Price { get; set; } 16 | 17 | public virtual ICollection OrderDetails { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/Pages/Error.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ErrorModel 3 | @{ 4 | ViewData["Title"] = "Error"; 5 | } 6 | 7 |

Error.

8 |

An error occurred while processing your request.

9 | 10 | @if (Model.ShowRequestId) 11 | { 12 |

13 | Request ID: @Model.RequestId 14 |

15 | } 16 | 17 |

Development Mode

18 |

19 | Swapping to the Development environment displays detailed information about the error that occurred. 20 |

21 |

22 | The Development environment shouldn't be enabled for deployed applications. 23 | It can result in displaying sensitive information from exceptions to end users. 24 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development 25 | and restarting the app. 26 |

27 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/Pages/Error.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.AspNetCore.Mvc.RazorPages; 4 | 5 | namespace ContosoPizza.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 | 28 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/Pages/Index.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model IndexModel 3 | @{ 4 | ViewData["Title"] = "Home page"; 5 | } 6 | 7 |
8 |

Welcome

9 |

Learn about building Web apps with ASP.NET Core.

10 |
11 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/Pages/Index.cshtml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Microsoft.AspNetCore.Mvc.RazorPages; 3 | 4 | namespace ContosoPizza.Pages; 5 | 6 | public class IndexModel : PageModel 7 | { 8 | private readonly ILogger _logger; 9 | 10 | public IndexModel(ILogger logger) 11 | { 12 | _logger = logger; 13 | } 14 | 15 | public void OnGet() 16 | { 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/Pages/Privacy.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model PrivacyModel 3 | @{ 4 | ViewData["Title"] = "Privacy Policy"; 5 | } 6 |

@ViewData["Title"]

7 | 8 |

Use this page to detail your site's privacy policy.

9 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/Pages/Privacy.cshtml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Microsoft.AspNetCore.Mvc.RazorPages; 3 | 4 | namespace ContosoPizza.Pages; 5 | 6 | public class PrivacyModel : PageModel 7 | { 8 | private readonly ILogger _logger; 9 | 10 | public PrivacyModel(ILogger logger) 11 | { 12 | _logger = logger; 13 | } 14 | 15 | public void OnGet() 16 | { 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/Pages/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewData["Title"] - ContosoPizza 7 | 8 | 9 | 10 | 11 | 12 |
13 | 32 |
33 |
34 |
35 | @RenderBody() 36 |
37 |
38 | 39 |
40 |
41 | © 2022 - ContosoPizza - Privacy 42 |
43 |
44 | 45 | 46 | 47 | 48 | 49 | @await RenderSectionAsync("Scripts", required: false) 50 | 51 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/Pages/Shared/_Layout.cshtml.css: -------------------------------------------------------------------------------- 1 | /* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | for details on configuring this project to bundle and minify static web assets. */ 3 | 4 | a.navbar-brand { 5 | white-space: normal; 6 | text-align: center; 7 | word-break: break-all; 8 | } 9 | 10 | a { 11 | color: #0077cc; 12 | } 13 | 14 | .btn-primary { 15 | color: #fff; 16 | background-color: #1b6ec2; 17 | border-color: #1861ac; 18 | } 19 | 20 | .nav-pills .nav-link.active, .nav-pills .show > .nav-link { 21 | color: #fff; 22 | background-color: #1b6ec2; 23 | border-color: #1861ac; 24 | } 25 | 26 | .border-top { 27 | border-top: 1px solid #e5e5e5; 28 | } 29 | .border-bottom { 30 | border-bottom: 1px solid #e5e5e5; 31 | } 32 | 33 | .box-shadow { 34 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05); 35 | } 36 | 37 | button.accept-policy { 38 | font-size: 1rem; 39 | line-height: inherit; 40 | } 41 | 42 | .footer { 43 | position: absolute; 44 | bottom: 0; 45 | width: 100%; 46 | white-space: nowrap; 47 | line-height: 60px; 48 | } 49 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/Pages/Shared/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/Pages/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using ContosoPizza 2 | @namespace ContosoPizza.Pages 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/Pages/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/Program.cs: -------------------------------------------------------------------------------- 1 | var builder = WebApplication.CreateBuilder(args); 2 | 3 | // Add services to the container. 4 | builder.Services.AddRazorPages(); 5 | 6 | var app = builder.Build(); 7 | 8 | // Configure the HTTP request pipeline. 9 | if (!app.Environment.IsDevelopment()) 10 | { 11 | app.UseExceptionHandler("/Error"); 12 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. 13 | app.UseHsts(); 14 | } 15 | 16 | app.UseHttpsRedirection(); 17 | app.UseStaticFiles(); 18 | 19 | app.UseRouting(); 20 | 21 | app.UseAuthorization(); 22 | 23 | app.MapRazorPages(); 24 | 25 | app.Run(); 26 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:50563", 7 | "sslPort": 44353 8 | } 9 | }, 10 | "profiles": { 11 | "ContosoPizza": { 12 | "commandName": "Project", 13 | "dotnetRunMessages": true, 14 | "launchBrowser": true, 15 | "applicationUrl": "https://localhost:7244;http://localhost:5266", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "IIS Express": { 21 | "commandName": "IISExpress", 22 | "launchBrowser": true, 23 | "environmentVariables": { 24 | "ASPNETCORE_ENVIRONMENT": "Development" 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "DetailedErrors": true, 3 | "Logging": { 4 | "LogLevel": { 5 | "Default": "Information", 6 | "Microsoft.AspNetCore": "Warning" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-size: 14px; 3 | } 4 | 5 | @media (min-width: 768px) { 6 | html { 7 | font-size: 16px; 8 | } 9 | } 10 | 11 | html { 12 | position: relative; 13 | min-height: 100%; 14 | } 15 | 16 | body { 17 | margin-bottom: 60px; 18 | } -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDocs/ef-core-for-beginners/b846adad4ef68e7dba4468e89c659dcf0661c4c7/parts/3-web-sites/ContosoPizza/wwwroot/favicon.ico -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/wwwroot/js/site.js: -------------------------------------------------------------------------------- 1 | // Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | // for details on configuring this project to bundle and minify static web assets. 3 | 4 | // Write your JavaScript code. 5 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/wwwroot/lib/bootstrap/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2021 Twitter, Inc. 4 | Copyright (c) 2011-2021 The Bootstrap Authors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v5.1.0 (https://getbootstrap.com/) 3 | * Copyright 2011-2021 The Bootstrap Authors 4 | * Copyright 2011-2021 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */ 8 | *, 9 | *::before, 10 | *::after { 11 | box-sizing: border-box; 12 | } 13 | 14 | @media (prefers-reduced-motion: no-preference) { 15 | :root { 16 | scroll-behavior: smooth; 17 | } 18 | } 19 | 20 | body { 21 | margin: 0; 22 | font-family: var(--bs-body-font-family); 23 | font-size: var(--bs-body-font-size); 24 | font-weight: var(--bs-body-font-weight); 25 | line-height: var(--bs-body-line-height); 26 | color: var(--bs-body-color); 27 | text-align: var(--bs-body-text-align); 28 | background-color: var(--bs-body-bg); 29 | -webkit-text-size-adjust: 100%; 30 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 31 | } 32 | 33 | hr { 34 | margin: 1rem 0; 35 | color: inherit; 36 | background-color: currentColor; 37 | border: 0; 38 | opacity: 0.25; 39 | } 40 | 41 | hr:not([size]) { 42 | height: 1px; 43 | } 44 | 45 | h6, h5, h4, h3, h2, h1 { 46 | margin-top: 0; 47 | margin-bottom: 0.5rem; 48 | font-weight: 500; 49 | line-height: 1.2; 50 | } 51 | 52 | h1 { 53 | font-size: calc(1.375rem + 1.5vw); 54 | } 55 | @media (min-width: 1200px) { 56 | h1 { 57 | font-size: 2.5rem; 58 | } 59 | } 60 | 61 | h2 { 62 | font-size: calc(1.325rem + 0.9vw); 63 | } 64 | @media (min-width: 1200px) { 65 | h2 { 66 | font-size: 2rem; 67 | } 68 | } 69 | 70 | h3 { 71 | font-size: calc(1.3rem + 0.6vw); 72 | } 73 | @media (min-width: 1200px) { 74 | h3 { 75 | font-size: 1.75rem; 76 | } 77 | } 78 | 79 | h4 { 80 | font-size: calc(1.275rem + 0.3vw); 81 | } 82 | @media (min-width: 1200px) { 83 | h4 { 84 | font-size: 1.5rem; 85 | } 86 | } 87 | 88 | h5 { 89 | font-size: 1.25rem; 90 | } 91 | 92 | h6 { 93 | font-size: 1rem; 94 | } 95 | 96 | p { 97 | margin-top: 0; 98 | margin-bottom: 1rem; 99 | } 100 | 101 | abbr[title], 102 | abbr[data-bs-original-title] { 103 | -webkit-text-decoration: underline dotted; 104 | text-decoration: underline dotted; 105 | cursor: help; 106 | -webkit-text-decoration-skip-ink: none; 107 | text-decoration-skip-ink: none; 108 | } 109 | 110 | address { 111 | margin-bottom: 1rem; 112 | font-style: normal; 113 | line-height: inherit; 114 | } 115 | 116 | ol, 117 | ul { 118 | padding-left: 2rem; 119 | } 120 | 121 | ol, 122 | ul, 123 | dl { 124 | margin-top: 0; 125 | margin-bottom: 1rem; 126 | } 127 | 128 | ol ol, 129 | ul ul, 130 | ol ul, 131 | ul ol { 132 | margin-bottom: 0; 133 | } 134 | 135 | dt { 136 | font-weight: 700; 137 | } 138 | 139 | dd { 140 | margin-bottom: 0.5rem; 141 | margin-left: 0; 142 | } 143 | 144 | blockquote { 145 | margin: 0 0 1rem; 146 | } 147 | 148 | b, 149 | strong { 150 | font-weight: bolder; 151 | } 152 | 153 | small { 154 | font-size: 0.875em; 155 | } 156 | 157 | mark { 158 | padding: 0.2em; 159 | background-color: #fcf8e3; 160 | } 161 | 162 | sub, 163 | sup { 164 | position: relative; 165 | font-size: 0.75em; 166 | line-height: 0; 167 | vertical-align: baseline; 168 | } 169 | 170 | sub { 171 | bottom: -0.25em; 172 | } 173 | 174 | sup { 175 | top: -0.5em; 176 | } 177 | 178 | a { 179 | color: #0d6efd; 180 | text-decoration: underline; 181 | } 182 | a:hover { 183 | color: #0a58ca; 184 | } 185 | 186 | a:not([href]):not([class]), a:not([href]):not([class]):hover { 187 | color: inherit; 188 | text-decoration: none; 189 | } 190 | 191 | pre, 192 | code, 193 | kbd, 194 | samp { 195 | font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 196 | font-size: 1em; 197 | direction: ltr /* rtl:ignore */; 198 | unicode-bidi: bidi-override; 199 | } 200 | 201 | pre { 202 | display: block; 203 | margin-top: 0; 204 | margin-bottom: 1rem; 205 | overflow: auto; 206 | font-size: 0.875em; 207 | } 208 | pre code { 209 | font-size: inherit; 210 | color: inherit; 211 | word-break: normal; 212 | } 213 | 214 | code { 215 | font-size: 0.875em; 216 | color: #d63384; 217 | word-wrap: break-word; 218 | } 219 | a > code { 220 | color: inherit; 221 | } 222 | 223 | kbd { 224 | padding: 0.2rem 0.4rem; 225 | font-size: 0.875em; 226 | color: #fff; 227 | background-color: #212529; 228 | border-radius: 0.2rem; 229 | } 230 | kbd kbd { 231 | padding: 0; 232 | font-size: 1em; 233 | font-weight: 700; 234 | } 235 | 236 | figure { 237 | margin: 0 0 1rem; 238 | } 239 | 240 | img, 241 | svg { 242 | vertical-align: middle; 243 | } 244 | 245 | table { 246 | caption-side: bottom; 247 | border-collapse: collapse; 248 | } 249 | 250 | caption { 251 | padding-top: 0.5rem; 252 | padding-bottom: 0.5rem; 253 | color: #6c757d; 254 | text-align: left; 255 | } 256 | 257 | th { 258 | text-align: inherit; 259 | text-align: -webkit-match-parent; 260 | } 261 | 262 | thead, 263 | tbody, 264 | tfoot, 265 | tr, 266 | td, 267 | th { 268 | border-color: inherit; 269 | border-style: solid; 270 | border-width: 0; 271 | } 272 | 273 | label { 274 | display: inline-block; 275 | } 276 | 277 | button { 278 | border-radius: 0; 279 | } 280 | 281 | button:focus:not(:focus-visible) { 282 | outline: 0; 283 | } 284 | 285 | input, 286 | button, 287 | select, 288 | optgroup, 289 | textarea { 290 | margin: 0; 291 | font-family: inherit; 292 | font-size: inherit; 293 | line-height: inherit; 294 | } 295 | 296 | button, 297 | select { 298 | text-transform: none; 299 | } 300 | 301 | [role=button] { 302 | cursor: pointer; 303 | } 304 | 305 | select { 306 | word-wrap: normal; 307 | } 308 | select:disabled { 309 | opacity: 1; 310 | } 311 | 312 | [list]::-webkit-calendar-picker-indicator { 313 | display: none; 314 | } 315 | 316 | button, 317 | [type=button], 318 | [type=reset], 319 | [type=submit] { 320 | -webkit-appearance: button; 321 | } 322 | button:not(:disabled), 323 | [type=button]:not(:disabled), 324 | [type=reset]:not(:disabled), 325 | [type=submit]:not(:disabled) { 326 | cursor: pointer; 327 | } 328 | 329 | ::-moz-focus-inner { 330 | padding: 0; 331 | border-style: none; 332 | } 333 | 334 | textarea { 335 | resize: vertical; 336 | } 337 | 338 | fieldset { 339 | min-width: 0; 340 | padding: 0; 341 | margin: 0; 342 | border: 0; 343 | } 344 | 345 | legend { 346 | float: left; 347 | width: 100%; 348 | padding: 0; 349 | margin-bottom: 0.5rem; 350 | font-size: calc(1.275rem + 0.3vw); 351 | line-height: inherit; 352 | } 353 | @media (min-width: 1200px) { 354 | legend { 355 | font-size: 1.5rem; 356 | } 357 | } 358 | legend + * { 359 | clear: left; 360 | } 361 | 362 | ::-webkit-datetime-edit-fields-wrapper, 363 | ::-webkit-datetime-edit-text, 364 | ::-webkit-datetime-edit-minute, 365 | ::-webkit-datetime-edit-hour-field, 366 | ::-webkit-datetime-edit-day-field, 367 | ::-webkit-datetime-edit-month-field, 368 | ::-webkit-datetime-edit-year-field { 369 | padding: 0; 370 | } 371 | 372 | ::-webkit-inner-spin-button { 373 | height: auto; 374 | } 375 | 376 | [type=search] { 377 | outline-offset: -2px; 378 | -webkit-appearance: textfield; 379 | } 380 | 381 | /* rtl:raw: 382 | [type="tel"], 383 | [type="url"], 384 | [type="email"], 385 | [type="number"] { 386 | direction: ltr; 387 | } 388 | */ 389 | ::-webkit-search-decoration { 390 | -webkit-appearance: none; 391 | } 392 | 393 | ::-webkit-color-swatch-wrapper { 394 | padding: 0; 395 | } 396 | 397 | ::file-selector-button { 398 | font: inherit; 399 | } 400 | 401 | ::-webkit-file-upload-button { 402 | font: inherit; 403 | -webkit-appearance: button; 404 | } 405 | 406 | output { 407 | display: inline-block; 408 | } 409 | 410 | iframe { 411 | border: 0; 412 | } 413 | 414 | summary { 415 | display: list-item; 416 | cursor: pointer; 417 | } 418 | 419 | progress { 420 | vertical-align: baseline; 421 | } 422 | 423 | [hidden] { 424 | display: none !important; 425 | } 426 | 427 | /*# sourceMappingURL=bootstrap-reboot.css.map */ -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v5.1.0 (https://getbootstrap.com/) 3 | * Copyright 2011-2021 The Bootstrap Authors 4 | * Copyright 2011-2021 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important} 8 | /*# sourceMappingURL=bootstrap-reboot.min.css.map */ -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v5.1.0 (https://getbootstrap.com/) 3 | * Copyright 2011-2021 The Bootstrap Authors 4 | * Copyright 2011-2021 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */ 8 | *, 9 | *::before, 10 | *::after { 11 | box-sizing: border-box; 12 | } 13 | 14 | @media (prefers-reduced-motion: no-preference) { 15 | :root { 16 | scroll-behavior: smooth; 17 | } 18 | } 19 | 20 | body { 21 | margin: 0; 22 | font-family: var(--bs-body-font-family); 23 | font-size: var(--bs-body-font-size); 24 | font-weight: var(--bs-body-font-weight); 25 | line-height: var(--bs-body-line-height); 26 | color: var(--bs-body-color); 27 | text-align: var(--bs-body-text-align); 28 | background-color: var(--bs-body-bg); 29 | -webkit-text-size-adjust: 100%; 30 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 31 | } 32 | 33 | hr { 34 | margin: 1rem 0; 35 | color: inherit; 36 | background-color: currentColor; 37 | border: 0; 38 | opacity: 0.25; 39 | } 40 | 41 | hr:not([size]) { 42 | height: 1px; 43 | } 44 | 45 | h6, h5, h4, h3, h2, h1 { 46 | margin-top: 0; 47 | margin-bottom: 0.5rem; 48 | font-weight: 500; 49 | line-height: 1.2; 50 | } 51 | 52 | h1 { 53 | font-size: calc(1.375rem + 1.5vw); 54 | } 55 | @media (min-width: 1200px) { 56 | h1 { 57 | font-size: 2.5rem; 58 | } 59 | } 60 | 61 | h2 { 62 | font-size: calc(1.325rem + 0.9vw); 63 | } 64 | @media (min-width: 1200px) { 65 | h2 { 66 | font-size: 2rem; 67 | } 68 | } 69 | 70 | h3 { 71 | font-size: calc(1.3rem + 0.6vw); 72 | } 73 | @media (min-width: 1200px) { 74 | h3 { 75 | font-size: 1.75rem; 76 | } 77 | } 78 | 79 | h4 { 80 | font-size: calc(1.275rem + 0.3vw); 81 | } 82 | @media (min-width: 1200px) { 83 | h4 { 84 | font-size: 1.5rem; 85 | } 86 | } 87 | 88 | h5 { 89 | font-size: 1.25rem; 90 | } 91 | 92 | h6 { 93 | font-size: 1rem; 94 | } 95 | 96 | p { 97 | margin-top: 0; 98 | margin-bottom: 1rem; 99 | } 100 | 101 | abbr[title], 102 | abbr[data-bs-original-title] { 103 | -webkit-text-decoration: underline dotted; 104 | text-decoration: underline dotted; 105 | cursor: help; 106 | -webkit-text-decoration-skip-ink: none; 107 | text-decoration-skip-ink: none; 108 | } 109 | 110 | address { 111 | margin-bottom: 1rem; 112 | font-style: normal; 113 | line-height: inherit; 114 | } 115 | 116 | ol, 117 | ul { 118 | padding-right: 2rem; 119 | } 120 | 121 | ol, 122 | ul, 123 | dl { 124 | margin-top: 0; 125 | margin-bottom: 1rem; 126 | } 127 | 128 | ol ol, 129 | ul ul, 130 | ol ul, 131 | ul ol { 132 | margin-bottom: 0; 133 | } 134 | 135 | dt { 136 | font-weight: 700; 137 | } 138 | 139 | dd { 140 | margin-bottom: 0.5rem; 141 | margin-right: 0; 142 | } 143 | 144 | blockquote { 145 | margin: 0 0 1rem; 146 | } 147 | 148 | b, 149 | strong { 150 | font-weight: bolder; 151 | } 152 | 153 | small { 154 | font-size: 0.875em; 155 | } 156 | 157 | mark { 158 | padding: 0.2em; 159 | background-color: #fcf8e3; 160 | } 161 | 162 | sub, 163 | sup { 164 | position: relative; 165 | font-size: 0.75em; 166 | line-height: 0; 167 | vertical-align: baseline; 168 | } 169 | 170 | sub { 171 | bottom: -0.25em; 172 | } 173 | 174 | sup { 175 | top: -0.5em; 176 | } 177 | 178 | a { 179 | color: #0d6efd; 180 | text-decoration: underline; 181 | } 182 | a:hover { 183 | color: #0a58ca; 184 | } 185 | 186 | a:not([href]):not([class]), a:not([href]):not([class]):hover { 187 | color: inherit; 188 | text-decoration: none; 189 | } 190 | 191 | pre, 192 | code, 193 | kbd, 194 | samp { 195 | font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 196 | font-size: 1em; 197 | direction: ltr ; 198 | unicode-bidi: bidi-override; 199 | } 200 | 201 | pre { 202 | display: block; 203 | margin-top: 0; 204 | margin-bottom: 1rem; 205 | overflow: auto; 206 | font-size: 0.875em; 207 | } 208 | pre code { 209 | font-size: inherit; 210 | color: inherit; 211 | word-break: normal; 212 | } 213 | 214 | code { 215 | font-size: 0.875em; 216 | color: #d63384; 217 | word-wrap: break-word; 218 | } 219 | a > code { 220 | color: inherit; 221 | } 222 | 223 | kbd { 224 | padding: 0.2rem 0.4rem; 225 | font-size: 0.875em; 226 | color: #fff; 227 | background-color: #212529; 228 | border-radius: 0.2rem; 229 | } 230 | kbd kbd { 231 | padding: 0; 232 | font-size: 1em; 233 | font-weight: 700; 234 | } 235 | 236 | figure { 237 | margin: 0 0 1rem; 238 | } 239 | 240 | img, 241 | svg { 242 | vertical-align: middle; 243 | } 244 | 245 | table { 246 | caption-side: bottom; 247 | border-collapse: collapse; 248 | } 249 | 250 | caption { 251 | padding-top: 0.5rem; 252 | padding-bottom: 0.5rem; 253 | color: #6c757d; 254 | text-align: right; 255 | } 256 | 257 | th { 258 | text-align: inherit; 259 | text-align: -webkit-match-parent; 260 | } 261 | 262 | thead, 263 | tbody, 264 | tfoot, 265 | tr, 266 | td, 267 | th { 268 | border-color: inherit; 269 | border-style: solid; 270 | border-width: 0; 271 | } 272 | 273 | label { 274 | display: inline-block; 275 | } 276 | 277 | button { 278 | border-radius: 0; 279 | } 280 | 281 | button:focus:not(:focus-visible) { 282 | outline: 0; 283 | } 284 | 285 | input, 286 | button, 287 | select, 288 | optgroup, 289 | textarea { 290 | margin: 0; 291 | font-family: inherit; 292 | font-size: inherit; 293 | line-height: inherit; 294 | } 295 | 296 | button, 297 | select { 298 | text-transform: none; 299 | } 300 | 301 | [role=button] { 302 | cursor: pointer; 303 | } 304 | 305 | select { 306 | word-wrap: normal; 307 | } 308 | select:disabled { 309 | opacity: 1; 310 | } 311 | 312 | [list]::-webkit-calendar-picker-indicator { 313 | display: none; 314 | } 315 | 316 | button, 317 | [type=button], 318 | [type=reset], 319 | [type=submit] { 320 | -webkit-appearance: button; 321 | } 322 | button:not(:disabled), 323 | [type=button]:not(:disabled), 324 | [type=reset]:not(:disabled), 325 | [type=submit]:not(:disabled) { 326 | cursor: pointer; 327 | } 328 | 329 | ::-moz-focus-inner { 330 | padding: 0; 331 | border-style: none; 332 | } 333 | 334 | textarea { 335 | resize: vertical; 336 | } 337 | 338 | fieldset { 339 | min-width: 0; 340 | padding: 0; 341 | margin: 0; 342 | border: 0; 343 | } 344 | 345 | legend { 346 | float: right; 347 | width: 100%; 348 | padding: 0; 349 | margin-bottom: 0.5rem; 350 | font-size: calc(1.275rem + 0.3vw); 351 | line-height: inherit; 352 | } 353 | @media (min-width: 1200px) { 354 | legend { 355 | font-size: 1.5rem; 356 | } 357 | } 358 | legend + * { 359 | clear: right; 360 | } 361 | 362 | ::-webkit-datetime-edit-fields-wrapper, 363 | ::-webkit-datetime-edit-text, 364 | ::-webkit-datetime-edit-minute, 365 | ::-webkit-datetime-edit-hour-field, 366 | ::-webkit-datetime-edit-day-field, 367 | ::-webkit-datetime-edit-month-field, 368 | ::-webkit-datetime-edit-year-field { 369 | padding: 0; 370 | } 371 | 372 | ::-webkit-inner-spin-button { 373 | height: auto; 374 | } 375 | 376 | [type=search] { 377 | outline-offset: -2px; 378 | -webkit-appearance: textfield; 379 | } 380 | 381 | [type="tel"], 382 | [type="url"], 383 | [type="email"], 384 | [type="number"] { 385 | direction: ltr; 386 | } 387 | ::-webkit-search-decoration { 388 | -webkit-appearance: none; 389 | } 390 | 391 | ::-webkit-color-swatch-wrapper { 392 | padding: 0; 393 | } 394 | 395 | ::file-selector-button { 396 | font: inherit; 397 | } 398 | 399 | ::-webkit-file-upload-button { 400 | font: inherit; 401 | -webkit-appearance: button; 402 | } 403 | 404 | output { 405 | display: inline-block; 406 | } 407 | 408 | iframe { 409 | border: 0; 410 | } 411 | 412 | summary { 413 | display: list-item; 414 | cursor: pointer; 415 | } 416 | 417 | progress { 418 | vertical-align: baseline; 419 | } 420 | 421 | [hidden] { 422 | display: none !important; 423 | } 424 | /*# sourceMappingURL=bootstrap-reboot.rtl.css.map */ -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v5.1.0 (https://getbootstrap.com/) 3 | * Copyright 2011-2021 The Bootstrap Authors 4 | * Copyright 2011-2021 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-right:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-right:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:right}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:right;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:right}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}[type=email],[type=number],[type=tel],[type=url]{direction:ltr}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important} 8 | /*# sourceMappingURL=bootstrap-reboot.rtl.min.css.map */ -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) .NET Foundation. All rights reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | these files except in compliance with the License. You may obtain a copy of the 5 | License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software distributed 10 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | specific language governing permissions and limitations under the License. 13 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js: -------------------------------------------------------------------------------- 1 | // Unobtrusive validation support library for jQuery and jQuery Validate 2 | // Copyright (c) .NET Foundation. All rights reserved. 3 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 4 | // @version v3.2.11 5 | !function(a){"function"==typeof define&&define.amd?define("jquery.validate.unobtrusive",["jquery-validation"],a):"object"==typeof module&&module.exports?module.exports=a(require("jquery-validation")):jQuery.validator.unobtrusive=a(jQuery)}(function(a){function e(a,e,n){a.rules[e]=n,a.message&&(a.messages[e]=a.message)}function n(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function t(a){return a.replace(/([!"#$%&'()*+,.\/:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function r(a){return a.substr(0,a.lastIndexOf(".")+1)}function i(a,e){return 0===a.indexOf("*.")&&(a=a.replace("*.",e)),a}function o(e,n){var r=a(this).find("[data-valmsg-for='"+t(n[0].name)+"']"),i=r.attr("data-valmsg-replace"),o=i?a.parseJSON(i)!==!1:null;r.removeClass("field-validation-valid").addClass("field-validation-error"),e.data("unobtrusiveContainer",r),o?(r.empty(),e.removeClass("input-validation-error").appendTo(r)):e.hide()}function d(e,n){var t=a(this).find("[data-valmsg-summary=true]"),r=t.find("ul");r&&r.length&&n.errorList.length&&(r.empty(),t.addClass("validation-summary-errors").removeClass("validation-summary-valid"),a.each(n.errorList,function(){a("
  • ").html(this.message).appendTo(r)}))}function s(e){var n=e.data("unobtrusiveContainer");if(n){var t=n.attr("data-valmsg-replace"),r=t?a.parseJSON(t):null;n.addClass("field-validation-valid").removeClass("field-validation-error"),e.removeData("unobtrusiveContainer"),r&&n.empty()}}function l(e){var n=a(this),t="__jquery_unobtrusive_validation_form_reset";if(!n.data(t)){n.data(t,!0);try{n.data("validator").resetForm()}finally{n.removeData(t)}n.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors"),n.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}}function u(e){var n=a(e),t=n.data(v),r=a.proxy(l,e),i=f.unobtrusive.options||{},u=function(n,t){var r=i[n];r&&a.isFunction(r)&&r.apply(e,t)};return t||(t={options:{errorClass:i.errorClass||"input-validation-error",errorElement:i.errorElement||"span",errorPlacement:function(){o.apply(e,arguments),u("errorPlacement",arguments)},invalidHandler:function(){d.apply(e,arguments),u("invalidHandler",arguments)},messages:{},rules:{},success:function(){s.apply(e,arguments),u("success",arguments)}},attachValidation:function(){n.off("reset."+v,r).on("reset."+v,r).validate(this.options)},validate:function(){return n.validate(),n.valid()}},n.data(v,t)),t}var m,f=a.validator,v="unobtrusiveValidation";return f.unobtrusive={adapters:[],parseElement:function(e,n){var t,r,i,o=a(e),d=o.parents("form")[0];d&&(t=u(d),t.options.rules[e.name]=r={},t.options.messages[e.name]=i={},a.each(this.adapters,function(){var n="data-val-"+this.name,t=o.attr(n),s={};void 0!==t&&(n+="-",a.each(this.params,function(){s[this]=o.attr(n+this)}),this.adapt({element:e,form:d,message:t,params:s,rules:r,messages:i}))}),a.extend(r,{__dummy__:!0}),n||t.attachValidation())},parse:function(e){var n=a(e),t=n.parents().addBack().filter("form").add(n.find("form")).has("[data-val=true]");n.find("[data-val=true]").each(function(){f.unobtrusive.parseElement(this,!0)}),t.each(function(){var a=u(this);a&&a.attachValidation()})}},m=f.unobtrusive.adapters,m.add=function(a,e,n){return n||(n=e,e=[]),this.push({name:a,params:e,adapt:n}),this},m.addBool=function(a,n){return this.add(a,function(t){e(t,n||a,!0)})},m.addMinMax=function(a,n,t,r,i,o){return this.add(a,[i||"min",o||"max"],function(a){var i=a.params.min,o=a.params.max;i&&o?e(a,r,[i,o]):i?e(a,n,i):o&&e(a,t,o)})},m.addSingleVal=function(a,n,t){return this.add(a,[n||"val"],function(r){e(r,t||a,r.params[n])})},f.addMethod("__dummy__",function(a,e,n){return!0}),f.addMethod("regex",function(a,e,n){var t;return!!this.optional(e)||(t=new RegExp(n).exec(a),t&&0===t.index&&t[0].length===a.length)}),f.addMethod("nonalphamin",function(a,e,n){var t;return n&&(t=a.match(/\W/g),t=t&&t.length>=n),t}),f.methods.extension?(m.addSingleVal("accept","mimtype"),m.addSingleVal("extension","extension")):m.addSingleVal("extension","extension","accept"),m.addSingleVal("regex","pattern"),m.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"),m.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range"),m.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength"),m.add("equalto",["other"],function(n){var o=r(n.element.name),d=n.params.other,s=i(d,o),l=a(n.form).find(":input").filter("[name='"+t(s)+"']")[0];e(n,"equalTo",l)}),m.add("required",function(a){"INPUT"===a.element.tagName.toUpperCase()&&"CHECKBOX"===a.element.type.toUpperCase()||e(a,"required",!0)}),m.add("remote",["url","type","additionalfields"],function(o){var d={url:o.params.url,type:o.params.type||"GET",data:{}},s=r(o.element.name);a.each(n(o.params.additionalfields||o.element.name),function(e,n){var r=i(n,s);d.data[r]=function(){var e=a(o.form).find(":input").filter("[name='"+t(r)+"']");return e.is(":checkbox")?e.filter(":checked").val()||e.filter(":hidden").val()||"":e.is(":radio")?e.filter(":checked").val()||"":e.val()}}),e(o,"remote",d)}),m.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&e(a,"minlength",a.params.min),a.params.nonalphamin&&e(a,"nonalphamin",a.params.nonalphamin),a.params.regex&&e(a,"regex",a.params.regex)}),m.add("fileextensions",["extensions"],function(a){e(a,"extension",a.params.extensions)}),a(function(){f.unobtrusive.parse(document)}),f.unobtrusive}); 6 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/wwwroot/lib/jquery-validation/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright Jörn Zaefferer 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /parts/3-web-sites/ContosoPizza/wwwroot/lib/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright JS Foundation and other contributors, https://js.foundation/ 2 | 3 | This software consists of voluntary contributions made by many 4 | individuals. For exact contribution history, see the revision history 5 | available at https://github.com/jquery/jquery 6 | 7 | The following license applies to all parts of this software except as 8 | documented below: 9 | 10 | ==== 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining 13 | a copy of this software and associated documentation files (the 14 | "Software"), to deal in the Software without restriction, including 15 | without limitation the rights to use, copy, modify, merge, publish, 16 | distribute, sublicense, and/or sell copies of the Software, and to 17 | permit persons to whom the Software is furnished to do so, subject to 18 | the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | ==== 32 | 33 | All files located in the node_modules and external directories are 34 | externally maintained libraries used by this software which have their 35 | own licenses; we recommend you read them, as their terms may differ from 36 | the terms above. 37 | -------------------------------------------------------------------------------- /parts/4-database-providers/ContosoPizza/ContosoPizza.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | runtime; build; native; contentfiles; analyzers; buildtransitive 13 | all 14 | 15 | 16 | 17 | runtime; build; native; contentfiles; analyzers; buildtransitive 18 | all 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /parts/4-database-providers/ContosoPizza/Data/ContosoPizzaContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | using ContosoPizza.Models; 6 | 7 | namespace ContosoPizza.Data 8 | { 9 | public partial class ContosoPizzaContext : DbContext 10 | { 11 | public ContosoPizzaContext() 12 | { 13 | 14 | } 15 | 16 | public ContosoPizzaContext(DbContextOptions options) 17 | : base(options) 18 | { 19 | } 20 | 21 | public virtual DbSet Customers { get; set; } = null!; 22 | public virtual DbSet Orders { get; set; } = null!; 23 | public virtual DbSet OrderDetails { get; set; } = null!; 24 | public virtual DbSet Products { get; set; } = null!; 25 | 26 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 27 | { 28 | // Keep your connection strings separate from your code! 29 | // Secure connection string guidance: https://aka.ms/ef-core-connection-strings 30 | // 31 | // optionsBuilder.UseSqlServer("Connection String Here"); 32 | 33 | 34 | } 35 | 36 | protected override void OnModelCreating(ModelBuilder modelBuilder) 37 | { 38 | OnModelCreatingPartial(modelBuilder); 39 | } 40 | 41 | partial void OnModelCreatingPartial(ModelBuilder modelBuilder); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /parts/4-database-providers/ContosoPizza/Models/Customer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ContosoPizza.Models 5 | { 6 | public partial class Customer 7 | { 8 | public Customer() 9 | { 10 | Orders = new HashSet(); 11 | } 12 | 13 | public int Id { get; set; } 14 | public string FirstName { get; set; } = null!; 15 | public string LastName { get; set; } = null!; 16 | public string? Address { get; set; } 17 | public string? Phone { get; set; } 18 | public string? Email { get; set; } 19 | 20 | public virtual ICollection Orders { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /parts/4-database-providers/ContosoPizza/Models/Order.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ContosoPizza.Models 5 | { 6 | public partial class Order 7 | { 8 | public Order() 9 | { 10 | OrderDetails = new HashSet(); 11 | } 12 | 13 | public int Id { get; set; } 14 | public DateTime OrderPlaced { get; set; } 15 | public DateTime? OrderFulfilled { get; set; } 16 | public int CustomerId { get; set; } 17 | 18 | public virtual Customer Customer { get; set; } = null!; 19 | public virtual ICollection OrderDetails { get; set; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /parts/4-database-providers/ContosoPizza/Models/OrderDetail.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ContosoPizza.Models 5 | { 6 | public partial class OrderDetail 7 | { 8 | public int Id { get; set; } 9 | public int Quantity { get; set; } 10 | public int ProductId { get; set; } 11 | public int OrderId { get; set; } 12 | 13 | public virtual Order Order { get; set; } = null!; 14 | public virtual Product Product { get; set; } = null!; 15 | } 16 | } -------------------------------------------------------------------------------- /parts/4-database-providers/ContosoPizza/Models/Product.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ContosoPizza.Models 5 | { 6 | public partial class Product 7 | { 8 | public Product() 9 | { 10 | OrderDetails = new HashSet(); 11 | } 12 | 13 | public int Id { get; set; } 14 | public string Name { get; set; } = null!; 15 | public decimal Price { get; set; } 16 | 17 | public virtual ICollection OrderDetails { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /parts/4-database-providers/ContosoPizza/Program.cs: -------------------------------------------------------------------------------- 1 | using ContosoPizza.Data; 2 | using ContosoPizza.Models; 3 | 4 | using ContosoPizzaContext context = new ContosoPizzaContext(); 5 | 6 | Product veggieSpecial = new Product() 7 | { 8 | Name = "Veggie Special Pizza", 9 | Price = 9.99M 10 | }; 11 | context.Products.Add(veggieSpecial); 12 | 13 | Product deluxeMeat = new Product() 14 | { 15 | Name = "Deluxe Meat Pizza", 16 | Price = 12.99M 17 | }; 18 | context.Add(deluxeMeat); 19 | 20 | context.SaveChanges(); 21 | 22 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/ContosoPizza.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | all 12 | runtime; build; native; contentfiles; analyzers; buildtransitive 13 | 14 | 15 | 16 | all 17 | runtime; build; native; contentfiles; analyzers; buildtransitive 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Data/ContosoPizzaContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | using ContosoPizza.Models; 6 | 7 | namespace ContosoPizza.Data 8 | { 9 | public partial class ContosoPizzaContext : DbContext 10 | { 11 | public ContosoPizzaContext() 12 | { 13 | } 14 | 15 | public ContosoPizzaContext(DbContextOptions options) 16 | : base(options) 17 | { 18 | } 19 | 20 | public virtual DbSet Customers { get; set; } = null!; 21 | public virtual DbSet Orders { get; set; } = null!; 22 | public virtual DbSet OrderDetails { get; set; } = null!; 23 | public virtual DbSet Products { get; set; } = null!; 24 | 25 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 26 | { 27 | 28 | } 29 | 30 | protected override void OnModelCreating(ModelBuilder modelBuilder) 31 | { 32 | OnModelCreatingPartial(modelBuilder); 33 | } 34 | 35 | partial void OnModelCreatingPartial(ModelBuilder modelBuilder); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Models/Customer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.ComponentModel.DataAnnotations.Schema; 5 | using Microsoft.EntityFrameworkCore; 6 | 7 | namespace ContosoPizza.Models 8 | { 9 | public partial class Customer 10 | { 11 | public Customer() 12 | { 13 | Orders = new HashSet(); 14 | } 15 | 16 | [Key] 17 | public int Id { get; set; } 18 | public string FirstName { get; set; } = null!; 19 | public string LastName { get; set; } = null!; 20 | public string? Address { get; set; } 21 | public string? Phone { get; set; } 22 | public string? Email { get; set; } 23 | 24 | [InverseProperty("Customer")] 25 | public virtual ICollection Orders { get; set; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Models/Order.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.ComponentModel.DataAnnotations.Schema; 5 | using Microsoft.EntityFrameworkCore; 6 | 7 | namespace ContosoPizza.Models 8 | { 9 | [Index("CustomerId", Name = "IX_Orders_CustomerId")] 10 | public partial class Order 11 | { 12 | public Order() 13 | { 14 | OrderDetails = new HashSet(); 15 | } 16 | 17 | [Key] 18 | public int Id { get; set; } 19 | public DateTime OrderPlaced { get; set; } 20 | public DateTime? OrderFulfilled { get; set; } 21 | public int CustomerId { get; set; } 22 | 23 | [ForeignKey("CustomerId")] 24 | [InverseProperty("Orders")] 25 | public virtual Customer Customer { get; set; } = null!; 26 | [InverseProperty("Order")] 27 | public virtual ICollection OrderDetails { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Models/OrderDetail.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.ComponentModel.DataAnnotations.Schema; 5 | using Microsoft.EntityFrameworkCore; 6 | 7 | namespace ContosoPizza.Models 8 | { 9 | [Index("OrderId", Name = "IX_OrderDetails_OrderId")] 10 | [Index("ProductId", Name = "IX_OrderDetails_ProductId")] 11 | public partial class OrderDetail 12 | { 13 | [Key] 14 | public int Id { get; set; } 15 | public int Quantity { get; set; } 16 | public int ProductId { get; set; } 17 | public int OrderId { get; set; } 18 | 19 | [ForeignKey("OrderId")] 20 | [InverseProperty("OrderDetails")] 21 | public virtual Order Order { get; set; } = null!; 22 | [ForeignKey("ProductId")] 23 | [InverseProperty("OrderDetails")] 24 | public virtual Product Product { get; set; } = null!; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Models/Product.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.ComponentModel.DataAnnotations.Schema; 5 | using Microsoft.EntityFrameworkCore; 6 | 7 | namespace ContosoPizza.Models 8 | { 9 | public partial class Product 10 | { 11 | public Product() 12 | { 13 | OrderDetails = new HashSet(); 14 | } 15 | 16 | [Key] 17 | public int Id { get; set; } 18 | public string Name { get; set; } = null!; 19 | [Column(TypeName = "decimal(6, 2)")] 20 | public decimal Price { get; set; } 21 | 22 | [InverseProperty("Product")] 23 | public virtual ICollection OrderDetails { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Pages/Customers/Create.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ContosoPizza.Pages.Customers.CreateModel 3 | 4 | @{ 5 | ViewData["Title"] = "Create"; 6 | } 7 | 8 |

    Create

    9 | 10 |

    Customer

    11 |
    12 |
    13 |
    14 |
    15 |
    16 |
    17 | 18 | 19 | 20 |
    21 |
    22 | 23 | 24 | 25 |
    26 |
    27 | 28 | 29 | 30 |
    31 |
    32 | 33 | 34 | 35 |
    36 |
    37 | 38 | 39 | 40 |
    41 |
    42 | 43 |
    44 |
    45 |
    46 |
    47 | 48 |
    49 | Back to List 50 |
    51 | 52 | @section Scripts { 53 | @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} 54 | } 55 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Pages/Customers/Create.cshtml.cs: -------------------------------------------------------------------------------- 1 | #nullable disable 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.AspNetCore.Mvc.RazorPages; 8 | using Microsoft.AspNetCore.Mvc.Rendering; 9 | using ContosoPizza.Data; 10 | using ContosoPizza.Models; 11 | 12 | namespace ContosoPizza.Pages.Customers 13 | { 14 | public class CreateModel : PageModel 15 | { 16 | private readonly ContosoPizza.Data.ContosoPizzaContext _context; 17 | 18 | public CreateModel(ContosoPizza.Data.ContosoPizzaContext context) 19 | { 20 | _context = context; 21 | } 22 | 23 | public IActionResult OnGet() 24 | { 25 | return Page(); 26 | } 27 | 28 | [BindProperty] 29 | public Customer Customer { get; set; } 30 | 31 | // To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD 32 | public async Task OnPostAsync() 33 | { 34 | if (!ModelState.IsValid) 35 | { 36 | return Page(); 37 | } 38 | 39 | _context.Customers.Add(Customer); 40 | await _context.SaveChangesAsync(); 41 | 42 | return RedirectToPage("./Index"); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Pages/Customers/Delete.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ContosoPizza.Pages.Customers.DeleteModel 3 | 4 | @{ 5 | ViewData["Title"] = "Delete"; 6 | } 7 | 8 |

    Delete

    9 | 10 |

    Are you sure you want to delete this?

    11 |
    12 |

    Customer

    13 |
    14 |
    15 |
    16 | @Html.DisplayNameFor(model => model.Customer.FirstName) 17 |
    18 |
    19 | @Html.DisplayFor(model => model.Customer.FirstName) 20 |
    21 |
    22 | @Html.DisplayNameFor(model => model.Customer.LastName) 23 |
    24 |
    25 | @Html.DisplayFor(model => model.Customer.LastName) 26 |
    27 |
    28 | @Html.DisplayNameFor(model => model.Customer.Address) 29 |
    30 |
    31 | @Html.DisplayFor(model => model.Customer.Address) 32 |
    33 |
    34 | @Html.DisplayNameFor(model => model.Customer.Phone) 35 |
    36 |
    37 | @Html.DisplayFor(model => model.Customer.Phone) 38 |
    39 |
    40 | @Html.DisplayNameFor(model => model.Customer.Email) 41 |
    42 |
    43 | @Html.DisplayFor(model => model.Customer.Email) 44 |
    45 |
    46 | 47 |
    48 | 49 | | 50 | Back to List 51 |
    52 |
    53 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Pages/Customers/Delete.cshtml.cs: -------------------------------------------------------------------------------- 1 | #nullable disable 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.AspNetCore.Mvc.RazorPages; 8 | using Microsoft.EntityFrameworkCore; 9 | using ContosoPizza.Data; 10 | using ContosoPizza.Models; 11 | 12 | namespace ContosoPizza.Pages.Customers 13 | { 14 | public class DeleteModel : PageModel 15 | { 16 | private readonly ContosoPizza.Data.ContosoPizzaContext _context; 17 | 18 | public DeleteModel(ContosoPizza.Data.ContosoPizzaContext context) 19 | { 20 | _context = context; 21 | } 22 | 23 | [BindProperty] 24 | public Customer Customer { get; set; } 25 | 26 | public async Task OnGetAsync(int? id) 27 | { 28 | if (id == null) 29 | { 30 | return NotFound(); 31 | } 32 | 33 | Customer = await _context.Customers.FirstOrDefaultAsync(m => m.Id == id); 34 | 35 | if (Customer == null) 36 | { 37 | return NotFound(); 38 | } 39 | return Page(); 40 | } 41 | 42 | public async Task OnPostAsync(int? id) 43 | { 44 | if (id == null) 45 | { 46 | return NotFound(); 47 | } 48 | 49 | Customer = await _context.Customers.FindAsync(id); 50 | 51 | if (Customer != null) 52 | { 53 | _context.Customers.Remove(Customer); 54 | await _context.SaveChangesAsync(); 55 | } 56 | 57 | return RedirectToPage("./Index"); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Pages/Customers/Details.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ContosoPizza.Pages.Customers.DetailsModel 3 | 4 | @{ 5 | ViewData["Title"] = "Details"; 6 | } 7 | 8 |

    Details

    9 | 10 |
    11 |

    Customer

    12 |
    13 |
    14 |
    15 | @Html.DisplayNameFor(model => model.Customer.FirstName) 16 |
    17 |
    18 | @Html.DisplayFor(model => model.Customer.FirstName) 19 |
    20 |
    21 | @Html.DisplayNameFor(model => model.Customer.LastName) 22 |
    23 |
    24 | @Html.DisplayFor(model => model.Customer.LastName) 25 |
    26 |
    27 | @Html.DisplayNameFor(model => model.Customer.Address) 28 |
    29 |
    30 | @Html.DisplayFor(model => model.Customer.Address) 31 |
    32 |
    33 | @Html.DisplayNameFor(model => model.Customer.Phone) 34 |
    35 |
    36 | @Html.DisplayFor(model => model.Customer.Phone) 37 |
    38 |
    39 | @Html.DisplayNameFor(model => model.Customer.Email) 40 |
    41 |
    42 | @Html.DisplayFor(model => model.Customer.Email) 43 |
    44 |
    45 |
    46 | 47 | @if (Model.Customer.Orders.Any()) 48 | { 49 | 50 | 51 | 52 | 55 | 58 | 61 | 64 | 65 | 66 | 67 | @foreach (var item in Model.Customer.Orders) { 68 | 69 | 72 | 75 | 78 | 92 | 93 | } 94 | 95 |
    53 | Order ID 54 | 56 | Order Time 57 | 59 | Fulfilled Time 60 | 62 | Order Details 63 |
    70 | @Html.DisplayFor(modelItem => item.Id) 71 | 73 | @Html.DisplayFor(modelItem => item.OrderPlaced) 74 | 76 | @Html.DisplayFor(modelItem => item.OrderFulfilled) 77 | 79 | 80 | @foreach (var od in item.OrderDetails) 81 | { 82 | 83 | 84 | 87 | 88 | 89 | } 90 |
    @od.Quantity qty@od.Product.Name@od.Product.Price
    91 |
    96 | } 97 |
    98 | Edit | 99 | Back to List 100 |
    101 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Pages/Customers/Details.cshtml.cs: -------------------------------------------------------------------------------- 1 | #nullable disable 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.AspNetCore.Mvc.RazorPages; 8 | using Microsoft.EntityFrameworkCore; 9 | using ContosoPizza.Data; 10 | using ContosoPizza.Models; 11 | 12 | namespace ContosoPizza.Pages.Customers 13 | { 14 | public class DetailsModel : PageModel 15 | { 16 | private readonly ContosoPizza.Data.ContosoPizzaContext _context; 17 | 18 | public DetailsModel(ContosoPizza.Data.ContosoPizzaContext context) 19 | { 20 | _context = context; 21 | } 22 | 23 | public Customer Customer { get; set; } 24 | 25 | public async Task OnGetAsync(int? id) 26 | { 27 | if (id == null) 28 | { 29 | return NotFound(); 30 | } 31 | 32 | Customer = await _context.Customers 33 | .Include(c => c.Orders) 34 | .ThenInclude(o => o.OrderDetails) 35 | .ThenInclude(od => od.Product) 36 | .FirstOrDefaultAsync(m => m.Id == id); 37 | 38 | 39 | if (Customer == null) 40 | { 41 | return NotFound(); 42 | } 43 | return Page(); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Pages/Customers/Edit.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ContosoPizza.Pages.Customers.EditModel 3 | 4 | @{ 5 | ViewData["Title"] = "Edit"; 6 | } 7 | 8 |

    Edit

    9 | 10 |

    Customer

    11 |
    12 |
    13 |
    14 |
    15 |
    16 | 17 |
    18 | 19 | 20 | 21 |
    22 |
    23 | 24 | 25 | 26 |
    27 |
    28 | 29 | 30 | 31 |
    32 |
    33 | 34 | 35 | 36 |
    37 |
    38 | 39 | 40 | 41 |
    42 |
    43 | 44 |
    45 |
    46 |
    47 |
    48 | 49 |
    50 | Back to List 51 |
    52 | 53 | @section Scripts { 54 | @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} 55 | } 56 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Pages/Customers/Edit.cshtml.cs: -------------------------------------------------------------------------------- 1 | #nullable disable 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.AspNetCore.Mvc.RazorPages; 8 | using Microsoft.AspNetCore.Mvc.Rendering; 9 | using Microsoft.EntityFrameworkCore; 10 | using ContosoPizza.Data; 11 | using ContosoPizza.Models; 12 | 13 | namespace ContosoPizza.Pages.Customers 14 | { 15 | public class EditModel : PageModel 16 | { 17 | private readonly ContosoPizza.Data.ContosoPizzaContext _context; 18 | 19 | public EditModel(ContosoPizza.Data.ContosoPizzaContext context) 20 | { 21 | _context = context; 22 | } 23 | 24 | [BindProperty] 25 | public Customer Customer { get; set; } 26 | 27 | public async Task OnGetAsync(int? id) 28 | { 29 | if (id == null) 30 | { 31 | return NotFound(); 32 | } 33 | 34 | Customer = await _context.Customers.FirstOrDefaultAsync(m => m.Id == id); 35 | 36 | if (Customer == null) 37 | { 38 | return NotFound(); 39 | } 40 | return Page(); 41 | } 42 | 43 | // To protect from overposting attacks, enable the specific properties you want to bind to. 44 | // For more details, see https://aka.ms/RazorPagesCRUD. 45 | public async Task OnPostAsync() 46 | { 47 | if (!ModelState.IsValid) 48 | { 49 | return Page(); 50 | } 51 | 52 | _context.Attach(Customer).State = EntityState.Modified; 53 | 54 | try 55 | { 56 | await _context.SaveChangesAsync(); 57 | } 58 | catch (DbUpdateConcurrencyException) 59 | { 60 | if (!CustomerExists(Customer.Id)) 61 | { 62 | return NotFound(); 63 | } 64 | else 65 | { 66 | throw; 67 | } 68 | } 69 | 70 | return RedirectToPage("./Index"); 71 | } 72 | 73 | private bool CustomerExists(int id) 74 | { 75 | return _context.Customers.Any(e => e.Id == id); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Pages/Customers/Index.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ContosoPizza.Pages.Customers.IndexModel 3 | 4 | @{ 5 | ViewData["Title"] = "Index"; 6 | } 7 | 8 |

    Index

    9 | 10 |

    11 | Create New 12 |

    13 | 14 | 15 | 16 | 19 | 22 | 25 | 28 | 31 | 34 | 35 | 36 | 37 | 38 | @foreach (var item in Model.Customer) { 39 | 40 | 43 | 46 | 49 | 52 | 55 | 58 | 63 | 64 | } 65 | 66 |
    17 | @Html.DisplayNameFor(model => model.Customer[0].FirstName) 18 | 20 | @Html.DisplayNameFor(model => model.Customer[0].LastName) 21 | 23 | @Html.DisplayNameFor(model => model.Customer[0].Address) 24 | 26 | @Html.DisplayNameFor(model => model.Customer[0].Phone) 27 | 29 | @Html.DisplayNameFor(model => model.Customer[0].Email) 30 | 32 | Total Orders 33 |
    41 | @Html.DisplayFor(modelItem => item.FirstName) 42 | 44 | @Html.DisplayFor(modelItem => item.LastName) 45 | 47 | @Html.DisplayFor(modelItem => item.Address) 48 | 50 | @Html.DisplayFor(modelItem => item.Phone) 51 | 53 | @Html.DisplayFor(modelItem => item.Email) 54 | 56 | @item.Orders.Count 57 | 59 | Edit | 60 | Details | 61 | Delete 62 |
    67 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Pages/Customers/Index.cshtml.cs: -------------------------------------------------------------------------------- 1 | #nullable disable 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.AspNetCore.Mvc.RazorPages; 8 | using Microsoft.EntityFrameworkCore; 9 | using ContosoPizza.Data; 10 | using ContosoPizza.Models; 11 | 12 | namespace ContosoPizza.Pages.Customers 13 | { 14 | public class IndexModel : PageModel 15 | { 16 | private readonly ContosoPizza.Data.ContosoPizzaContext _context; 17 | 18 | public IndexModel(ContosoPizza.Data.ContosoPizzaContext context) 19 | { 20 | _context = context; 21 | } 22 | 23 | public IList Customer { get;set; } 24 | 25 | public async Task OnGetAsync() 26 | { 27 | Customer = await _context.Customers 28 | .Include(c => c.Orders) 29 | .ToListAsync(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Pages/Error.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ErrorModel 3 | @{ 4 | ViewData["Title"] = "Error"; 5 | } 6 | 7 |

    Error.

    8 |

    An error occurred while processing your request.

    9 | 10 | @if (Model.ShowRequestId) 11 | { 12 |

    13 | Request ID: @Model.RequestId 14 |

    15 | } 16 | 17 |

    Development Mode

    18 |

    19 | Swapping to the Development environment displays detailed information about the error that occurred. 20 |

    21 |

    22 | The Development environment shouldn't be enabled for deployed applications. 23 | It can result in displaying sensitive information from exceptions to end users. 24 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development 25 | and restarting the app. 26 |

    27 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Pages/Error.cshtml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Microsoft.AspNetCore.Mvc.RazorPages; 3 | 4 | using System.Diagnostics; 5 | 6 | namespace ContosoPizza.Pages 7 | { 8 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] 9 | [IgnoreAntiforgeryToken] 10 | public class ErrorModel : PageModel 11 | { 12 | public string? RequestId { get; set; } 13 | 14 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 15 | 16 | private readonly ILogger _logger; 17 | 18 | public ErrorModel(ILogger logger) 19 | { 20 | _logger = logger; 21 | } 22 | 23 | public void OnGet() 24 | { 25 | RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Pages/Index.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model IndexModel 3 | @{ 4 | ViewData["Title"] = "Home page"; 5 | } 6 | 7 |
    8 |

    Welcome

    9 |

    Learn about building Web apps with ASP.NET Core.

    10 |
    11 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Pages/Index.cshtml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Microsoft.AspNetCore.Mvc.RazorPages; 3 | 4 | namespace ContosoPizza.Pages 5 | { 6 | public class IndexModel : PageModel 7 | { 8 | private readonly ILogger _logger; 9 | 10 | public IndexModel(ILogger logger) 11 | { 12 | _logger = logger; 13 | } 14 | 15 | public void OnGet() 16 | { 17 | 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Pages/Privacy.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model PrivacyModel 3 | @{ 4 | ViewData["Title"] = "Privacy Policy"; 5 | } 6 |

    @ViewData["Title"]

    7 | 8 |

    Use this page to detail your site's privacy policy.

    9 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Pages/Privacy.cshtml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Microsoft.AspNetCore.Mvc.RazorPages; 3 | 4 | namespace ContosoPizza.Pages 5 | { 6 | public class PrivacyModel : PageModel 7 | { 8 | private readonly ILogger _logger; 9 | 10 | public PrivacyModel(ILogger logger) 11 | { 12 | _logger = logger; 13 | } 14 | 15 | public void OnGet() 16 | { 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Pages/Products/Details.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ContosoPizza.Pages.Products.DetailsModel 3 | 4 | @{ 5 | ViewData["Title"] = "Details"; 6 | } 7 | 8 |

    Details

    9 | 10 |
    11 |

    Product

    12 |
    13 |
    14 |
    15 | @Html.DisplayNameFor(model => model.Product.Name) 16 |
    17 |
    18 | @Html.DisplayFor(model => model.Product.Name) 19 |
    20 |
    21 | @Html.DisplayNameFor(model => model.Product.Price) 22 |
    23 |
    24 | @Html.DisplayFor(model => model.Product.Price) 25 |
    26 |
    27 |
    28 | 29 | @if (Model.CustomerId > 0) 30 | { 31 | var customerName = $"{Model.Customer.FirstName} {Model.Customer.LastName}"; 32 | 33 | 36 | } 37 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Pages/Products/Details.cshtml.cs: -------------------------------------------------------------------------------- 1 | #nullable disable 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.AspNetCore.Mvc.RazorPages; 8 | using Microsoft.EntityFrameworkCore; 9 | using ContosoPizza.Data; 10 | using ContosoPizza.Models; 11 | 12 | namespace ContosoPizza.Pages.Products 13 | { 14 | public class DetailsModel : PageModel 15 | { 16 | private readonly ContosoPizza.Data.ContosoPizzaContext _context; 17 | 18 | public DetailsModel(ContosoPizza.Data.ContosoPizzaContext context) 19 | { 20 | _context = context; 21 | } 22 | 23 | public Product Product { get; set; } 24 | public int CustomerId { get; set; } 25 | public Customer Customer { get; set; } 26 | 27 | 28 | public async Task OnGetAsync(int? id, int customerId) 29 | { 30 | if (id == null) 31 | { 32 | return NotFound(); 33 | } 34 | CustomerId = customerId; 35 | 36 | Product = await _context.Products.FirstOrDefaultAsync(m => m.Id == id); 37 | 38 | if (Product == null) 39 | { 40 | return NotFound(); 41 | } 42 | 43 | if(CustomerId > 0) 44 | { 45 | Customer = await _context.Customers 46 | .Where(c => c.Id == CustomerId) 47 | .FirstOrDefaultAsync(); 48 | } 49 | 50 | return Page(); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Pages/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewData["Title"] - ContosoPizza 7 | 8 | 9 | 10 | 11 | 12 |
    13 | 35 |
    36 |
    37 |
    38 | @RenderBody() 39 |
    40 |
    41 | 42 |
    43 |
    44 | © 2022 - ContosoPizza - Privacy 45 |
    46 |
    47 | 48 | 49 | 50 | 51 | 52 | @await RenderSectionAsync("Scripts", required: false) 53 | 54 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Pages/Shared/_Layout.cshtml.css: -------------------------------------------------------------------------------- 1 | /* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | for details on configuring this project to bundle and minify static web assets. */ 3 | 4 | a.navbar-brand { 5 | white-space: normal; 6 | text-align: center; 7 | word-break: break-all; 8 | } 9 | 10 | a { 11 | color: #0077cc; 12 | } 13 | 14 | .btn-primary { 15 | color: #fff; 16 | background-color: #1b6ec2; 17 | border-color: #1861ac; 18 | } 19 | 20 | .nav-pills .nav-link.active, .nav-pills .show > .nav-link { 21 | color: #fff; 22 | background-color: #1b6ec2; 23 | border-color: #1861ac; 24 | } 25 | 26 | .border-top { 27 | border-top: 1px solid #e5e5e5; 28 | } 29 | .border-bottom { 30 | border-bottom: 1px solid #e5e5e5; 31 | } 32 | 33 | .box-shadow { 34 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05); 35 | } 36 | 37 | button.accept-policy { 38 | font-size: 1rem; 39 | line-height: inherit; 40 | } 41 | 42 | .footer { 43 | position: absolute; 44 | bottom: 0; 45 | width: 100%; 46 | white-space: nowrap; 47 | line-height: 60px; 48 | } 49 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Pages/Shared/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Pages/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using ContosoPizza 2 | @namespace ContosoPizza.Pages 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Pages/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Program.cs: -------------------------------------------------------------------------------- 1 | using ContosoPizza.Data; 2 | using Microsoft.EntityFrameworkCore; 3 | 4 | var builder = WebApplication.CreateBuilder(args); 5 | 6 | // Add services to the container. 7 | builder.Services.AddRazorPages(); 8 | 9 | // Add the "ContosoPizza" connection string to 10 | // Secrets Manager (secrets.json or dotnet user-secrets set) 11 | // before you run the app! 12 | builder.Services.AddDbContext(options => 13 | options 14 | .UseSqlServer(builder.Configuration.GetConnectionString("ContosoPizza"))); 15 | 16 | var app = builder.Build(); 17 | 18 | // Configure the HTTP request pipeline. 19 | if (!app.Environment.IsDevelopment()) 20 | { 21 | app.UseExceptionHandler("/Error"); 22 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. 23 | app.UseHsts(); 24 | } 25 | 26 | app.UseHttpsRedirection(); 27 | app.UseStaticFiles(); 28 | 29 | app.UseRouting(); 30 | 31 | app.UseAuthorization(); 32 | 33 | app.MapRazorPages(); 34 | 35 | app.Run(); 36 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:43569", 7 | "sslPort": 44365 8 | } 9 | }, 10 | "profiles": { 11 | "ContosoPizza": { 12 | "commandName": "Project", 13 | "dotnetRunMessages": true, 14 | "launchBrowser": true, 15 | "applicationUrl": "https://localhost:7197;http://localhost:5197", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "IIS Express": { 21 | "commandName": "IISExpress", 22 | "launchBrowser": true, 23 | "environmentVariables": { 24 | "ASPNETCORE_ENVIRONMENT": "Development" 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "DetailedErrors": true, 3 | "Logging": { 4 | "LogLevel": { 5 | "Default": "Information", 6 | "Microsoft.AspNetCore": "Warning" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-size: 14px; 3 | } 4 | 5 | @media (min-width: 768px) { 6 | html { 7 | font-size: 16px; 8 | } 9 | } 10 | 11 | html { 12 | position: relative; 13 | min-height: 100%; 14 | } 15 | 16 | body { 17 | margin-bottom: 60px; 18 | } -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftDocs/ef-core-for-beginners/b846adad4ef68e7dba4468e89c659dcf0661c4c7/parts/5-performance-tips/ContosoPizza/wwwroot/favicon.ico -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/wwwroot/js/site.js: -------------------------------------------------------------------------------- 1 | // Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | // for details on configuring this project to bundle and minify static web assets. 3 | 4 | // Write your JavaScript code. 5 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/wwwroot/lib/bootstrap/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2021 Twitter, Inc. 4 | Copyright (c) 2011-2021 The Bootstrap Authors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v5.1.0 (https://getbootstrap.com/) 3 | * Copyright 2011-2021 The Bootstrap Authors 4 | * Copyright 2011-2021 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */ 8 | *, 9 | *::before, 10 | *::after { 11 | box-sizing: border-box; 12 | } 13 | 14 | @media (prefers-reduced-motion: no-preference) { 15 | :root { 16 | scroll-behavior: smooth; 17 | } 18 | } 19 | 20 | body { 21 | margin: 0; 22 | font-family: var(--bs-body-font-family); 23 | font-size: var(--bs-body-font-size); 24 | font-weight: var(--bs-body-font-weight); 25 | line-height: var(--bs-body-line-height); 26 | color: var(--bs-body-color); 27 | text-align: var(--bs-body-text-align); 28 | background-color: var(--bs-body-bg); 29 | -webkit-text-size-adjust: 100%; 30 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 31 | } 32 | 33 | hr { 34 | margin: 1rem 0; 35 | color: inherit; 36 | background-color: currentColor; 37 | border: 0; 38 | opacity: 0.25; 39 | } 40 | 41 | hr:not([size]) { 42 | height: 1px; 43 | } 44 | 45 | h6, h5, h4, h3, h2, h1 { 46 | margin-top: 0; 47 | margin-bottom: 0.5rem; 48 | font-weight: 500; 49 | line-height: 1.2; 50 | } 51 | 52 | h1 { 53 | font-size: calc(1.375rem + 1.5vw); 54 | } 55 | @media (min-width: 1200px) { 56 | h1 { 57 | font-size: 2.5rem; 58 | } 59 | } 60 | 61 | h2 { 62 | font-size: calc(1.325rem + 0.9vw); 63 | } 64 | @media (min-width: 1200px) { 65 | h2 { 66 | font-size: 2rem; 67 | } 68 | } 69 | 70 | h3 { 71 | font-size: calc(1.3rem + 0.6vw); 72 | } 73 | @media (min-width: 1200px) { 74 | h3 { 75 | font-size: 1.75rem; 76 | } 77 | } 78 | 79 | h4 { 80 | font-size: calc(1.275rem + 0.3vw); 81 | } 82 | @media (min-width: 1200px) { 83 | h4 { 84 | font-size: 1.5rem; 85 | } 86 | } 87 | 88 | h5 { 89 | font-size: 1.25rem; 90 | } 91 | 92 | h6 { 93 | font-size: 1rem; 94 | } 95 | 96 | p { 97 | margin-top: 0; 98 | margin-bottom: 1rem; 99 | } 100 | 101 | abbr[title], 102 | abbr[data-bs-original-title] { 103 | -webkit-text-decoration: underline dotted; 104 | text-decoration: underline dotted; 105 | cursor: help; 106 | -webkit-text-decoration-skip-ink: none; 107 | text-decoration-skip-ink: none; 108 | } 109 | 110 | address { 111 | margin-bottom: 1rem; 112 | font-style: normal; 113 | line-height: inherit; 114 | } 115 | 116 | ol, 117 | ul { 118 | padding-left: 2rem; 119 | } 120 | 121 | ol, 122 | ul, 123 | dl { 124 | margin-top: 0; 125 | margin-bottom: 1rem; 126 | } 127 | 128 | ol ol, 129 | ul ul, 130 | ol ul, 131 | ul ol { 132 | margin-bottom: 0; 133 | } 134 | 135 | dt { 136 | font-weight: 700; 137 | } 138 | 139 | dd { 140 | margin-bottom: 0.5rem; 141 | margin-left: 0; 142 | } 143 | 144 | blockquote { 145 | margin: 0 0 1rem; 146 | } 147 | 148 | b, 149 | strong { 150 | font-weight: bolder; 151 | } 152 | 153 | small { 154 | font-size: 0.875em; 155 | } 156 | 157 | mark { 158 | padding: 0.2em; 159 | background-color: #fcf8e3; 160 | } 161 | 162 | sub, 163 | sup { 164 | position: relative; 165 | font-size: 0.75em; 166 | line-height: 0; 167 | vertical-align: baseline; 168 | } 169 | 170 | sub { 171 | bottom: -0.25em; 172 | } 173 | 174 | sup { 175 | top: -0.5em; 176 | } 177 | 178 | a { 179 | color: #0d6efd; 180 | text-decoration: underline; 181 | } 182 | a:hover { 183 | color: #0a58ca; 184 | } 185 | 186 | a:not([href]):not([class]), a:not([href]):not([class]):hover { 187 | color: inherit; 188 | text-decoration: none; 189 | } 190 | 191 | pre, 192 | code, 193 | kbd, 194 | samp { 195 | font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 196 | font-size: 1em; 197 | direction: ltr /* rtl:ignore */; 198 | unicode-bidi: bidi-override; 199 | } 200 | 201 | pre { 202 | display: block; 203 | margin-top: 0; 204 | margin-bottom: 1rem; 205 | overflow: auto; 206 | font-size: 0.875em; 207 | } 208 | pre code { 209 | font-size: inherit; 210 | color: inherit; 211 | word-break: normal; 212 | } 213 | 214 | code { 215 | font-size: 0.875em; 216 | color: #d63384; 217 | word-wrap: break-word; 218 | } 219 | a > code { 220 | color: inherit; 221 | } 222 | 223 | kbd { 224 | padding: 0.2rem 0.4rem; 225 | font-size: 0.875em; 226 | color: #fff; 227 | background-color: #212529; 228 | border-radius: 0.2rem; 229 | } 230 | kbd kbd { 231 | padding: 0; 232 | font-size: 1em; 233 | font-weight: 700; 234 | } 235 | 236 | figure { 237 | margin: 0 0 1rem; 238 | } 239 | 240 | img, 241 | svg { 242 | vertical-align: middle; 243 | } 244 | 245 | table { 246 | caption-side: bottom; 247 | border-collapse: collapse; 248 | } 249 | 250 | caption { 251 | padding-top: 0.5rem; 252 | padding-bottom: 0.5rem; 253 | color: #6c757d; 254 | text-align: left; 255 | } 256 | 257 | th { 258 | text-align: inherit; 259 | text-align: -webkit-match-parent; 260 | } 261 | 262 | thead, 263 | tbody, 264 | tfoot, 265 | tr, 266 | td, 267 | th { 268 | border-color: inherit; 269 | border-style: solid; 270 | border-width: 0; 271 | } 272 | 273 | label { 274 | display: inline-block; 275 | } 276 | 277 | button { 278 | border-radius: 0; 279 | } 280 | 281 | button:focus:not(:focus-visible) { 282 | outline: 0; 283 | } 284 | 285 | input, 286 | button, 287 | select, 288 | optgroup, 289 | textarea { 290 | margin: 0; 291 | font-family: inherit; 292 | font-size: inherit; 293 | line-height: inherit; 294 | } 295 | 296 | button, 297 | select { 298 | text-transform: none; 299 | } 300 | 301 | [role=button] { 302 | cursor: pointer; 303 | } 304 | 305 | select { 306 | word-wrap: normal; 307 | } 308 | select:disabled { 309 | opacity: 1; 310 | } 311 | 312 | [list]::-webkit-calendar-picker-indicator { 313 | display: none; 314 | } 315 | 316 | button, 317 | [type=button], 318 | [type=reset], 319 | [type=submit] { 320 | -webkit-appearance: button; 321 | } 322 | button:not(:disabled), 323 | [type=button]:not(:disabled), 324 | [type=reset]:not(:disabled), 325 | [type=submit]:not(:disabled) { 326 | cursor: pointer; 327 | } 328 | 329 | ::-moz-focus-inner { 330 | padding: 0; 331 | border-style: none; 332 | } 333 | 334 | textarea { 335 | resize: vertical; 336 | } 337 | 338 | fieldset { 339 | min-width: 0; 340 | padding: 0; 341 | margin: 0; 342 | border: 0; 343 | } 344 | 345 | legend { 346 | float: left; 347 | width: 100%; 348 | padding: 0; 349 | margin-bottom: 0.5rem; 350 | font-size: calc(1.275rem + 0.3vw); 351 | line-height: inherit; 352 | } 353 | @media (min-width: 1200px) { 354 | legend { 355 | font-size: 1.5rem; 356 | } 357 | } 358 | legend + * { 359 | clear: left; 360 | } 361 | 362 | ::-webkit-datetime-edit-fields-wrapper, 363 | ::-webkit-datetime-edit-text, 364 | ::-webkit-datetime-edit-minute, 365 | ::-webkit-datetime-edit-hour-field, 366 | ::-webkit-datetime-edit-day-field, 367 | ::-webkit-datetime-edit-month-field, 368 | ::-webkit-datetime-edit-year-field { 369 | padding: 0; 370 | } 371 | 372 | ::-webkit-inner-spin-button { 373 | height: auto; 374 | } 375 | 376 | [type=search] { 377 | outline-offset: -2px; 378 | -webkit-appearance: textfield; 379 | } 380 | 381 | /* rtl:raw: 382 | [type="tel"], 383 | [type="url"], 384 | [type="email"], 385 | [type="number"] { 386 | direction: ltr; 387 | } 388 | */ 389 | ::-webkit-search-decoration { 390 | -webkit-appearance: none; 391 | } 392 | 393 | ::-webkit-color-swatch-wrapper { 394 | padding: 0; 395 | } 396 | 397 | ::file-selector-button { 398 | font: inherit; 399 | } 400 | 401 | ::-webkit-file-upload-button { 402 | font: inherit; 403 | -webkit-appearance: button; 404 | } 405 | 406 | output { 407 | display: inline-block; 408 | } 409 | 410 | iframe { 411 | border: 0; 412 | } 413 | 414 | summary { 415 | display: list-item; 416 | cursor: pointer; 417 | } 418 | 419 | progress { 420 | vertical-align: baseline; 421 | } 422 | 423 | [hidden] { 424 | display: none !important; 425 | } 426 | 427 | /*# sourceMappingURL=bootstrap-reboot.css.map */ -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v5.1.0 (https://getbootstrap.com/) 3 | * Copyright 2011-2021 The Bootstrap Authors 4 | * Copyright 2011-2021 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important} 8 | /*# sourceMappingURL=bootstrap-reboot.min.css.map */ -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v5.1.0 (https://getbootstrap.com/) 3 | * Copyright 2011-2021 The Bootstrap Authors 4 | * Copyright 2011-2021 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */ 8 | *, 9 | *::before, 10 | *::after { 11 | box-sizing: border-box; 12 | } 13 | 14 | @media (prefers-reduced-motion: no-preference) { 15 | :root { 16 | scroll-behavior: smooth; 17 | } 18 | } 19 | 20 | body { 21 | margin: 0; 22 | font-family: var(--bs-body-font-family); 23 | font-size: var(--bs-body-font-size); 24 | font-weight: var(--bs-body-font-weight); 25 | line-height: var(--bs-body-line-height); 26 | color: var(--bs-body-color); 27 | text-align: var(--bs-body-text-align); 28 | background-color: var(--bs-body-bg); 29 | -webkit-text-size-adjust: 100%; 30 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 31 | } 32 | 33 | hr { 34 | margin: 1rem 0; 35 | color: inherit; 36 | background-color: currentColor; 37 | border: 0; 38 | opacity: 0.25; 39 | } 40 | 41 | hr:not([size]) { 42 | height: 1px; 43 | } 44 | 45 | h6, h5, h4, h3, h2, h1 { 46 | margin-top: 0; 47 | margin-bottom: 0.5rem; 48 | font-weight: 500; 49 | line-height: 1.2; 50 | } 51 | 52 | h1 { 53 | font-size: calc(1.375rem + 1.5vw); 54 | } 55 | @media (min-width: 1200px) { 56 | h1 { 57 | font-size: 2.5rem; 58 | } 59 | } 60 | 61 | h2 { 62 | font-size: calc(1.325rem + 0.9vw); 63 | } 64 | @media (min-width: 1200px) { 65 | h2 { 66 | font-size: 2rem; 67 | } 68 | } 69 | 70 | h3 { 71 | font-size: calc(1.3rem + 0.6vw); 72 | } 73 | @media (min-width: 1200px) { 74 | h3 { 75 | font-size: 1.75rem; 76 | } 77 | } 78 | 79 | h4 { 80 | font-size: calc(1.275rem + 0.3vw); 81 | } 82 | @media (min-width: 1200px) { 83 | h4 { 84 | font-size: 1.5rem; 85 | } 86 | } 87 | 88 | h5 { 89 | font-size: 1.25rem; 90 | } 91 | 92 | h6 { 93 | font-size: 1rem; 94 | } 95 | 96 | p { 97 | margin-top: 0; 98 | margin-bottom: 1rem; 99 | } 100 | 101 | abbr[title], 102 | abbr[data-bs-original-title] { 103 | -webkit-text-decoration: underline dotted; 104 | text-decoration: underline dotted; 105 | cursor: help; 106 | -webkit-text-decoration-skip-ink: none; 107 | text-decoration-skip-ink: none; 108 | } 109 | 110 | address { 111 | margin-bottom: 1rem; 112 | font-style: normal; 113 | line-height: inherit; 114 | } 115 | 116 | ol, 117 | ul { 118 | padding-right: 2rem; 119 | } 120 | 121 | ol, 122 | ul, 123 | dl { 124 | margin-top: 0; 125 | margin-bottom: 1rem; 126 | } 127 | 128 | ol ol, 129 | ul ul, 130 | ol ul, 131 | ul ol { 132 | margin-bottom: 0; 133 | } 134 | 135 | dt { 136 | font-weight: 700; 137 | } 138 | 139 | dd { 140 | margin-bottom: 0.5rem; 141 | margin-right: 0; 142 | } 143 | 144 | blockquote { 145 | margin: 0 0 1rem; 146 | } 147 | 148 | b, 149 | strong { 150 | font-weight: bolder; 151 | } 152 | 153 | small { 154 | font-size: 0.875em; 155 | } 156 | 157 | mark { 158 | padding: 0.2em; 159 | background-color: #fcf8e3; 160 | } 161 | 162 | sub, 163 | sup { 164 | position: relative; 165 | font-size: 0.75em; 166 | line-height: 0; 167 | vertical-align: baseline; 168 | } 169 | 170 | sub { 171 | bottom: -0.25em; 172 | } 173 | 174 | sup { 175 | top: -0.5em; 176 | } 177 | 178 | a { 179 | color: #0d6efd; 180 | text-decoration: underline; 181 | } 182 | a:hover { 183 | color: #0a58ca; 184 | } 185 | 186 | a:not([href]):not([class]), a:not([href]):not([class]):hover { 187 | color: inherit; 188 | text-decoration: none; 189 | } 190 | 191 | pre, 192 | code, 193 | kbd, 194 | samp { 195 | font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 196 | font-size: 1em; 197 | direction: ltr ; 198 | unicode-bidi: bidi-override; 199 | } 200 | 201 | pre { 202 | display: block; 203 | margin-top: 0; 204 | margin-bottom: 1rem; 205 | overflow: auto; 206 | font-size: 0.875em; 207 | } 208 | pre code { 209 | font-size: inherit; 210 | color: inherit; 211 | word-break: normal; 212 | } 213 | 214 | code { 215 | font-size: 0.875em; 216 | color: #d63384; 217 | word-wrap: break-word; 218 | } 219 | a > code { 220 | color: inherit; 221 | } 222 | 223 | kbd { 224 | padding: 0.2rem 0.4rem; 225 | font-size: 0.875em; 226 | color: #fff; 227 | background-color: #212529; 228 | border-radius: 0.2rem; 229 | } 230 | kbd kbd { 231 | padding: 0; 232 | font-size: 1em; 233 | font-weight: 700; 234 | } 235 | 236 | figure { 237 | margin: 0 0 1rem; 238 | } 239 | 240 | img, 241 | svg { 242 | vertical-align: middle; 243 | } 244 | 245 | table { 246 | caption-side: bottom; 247 | border-collapse: collapse; 248 | } 249 | 250 | caption { 251 | padding-top: 0.5rem; 252 | padding-bottom: 0.5rem; 253 | color: #6c757d; 254 | text-align: right; 255 | } 256 | 257 | th { 258 | text-align: inherit; 259 | text-align: -webkit-match-parent; 260 | } 261 | 262 | thead, 263 | tbody, 264 | tfoot, 265 | tr, 266 | td, 267 | th { 268 | border-color: inherit; 269 | border-style: solid; 270 | border-width: 0; 271 | } 272 | 273 | label { 274 | display: inline-block; 275 | } 276 | 277 | button { 278 | border-radius: 0; 279 | } 280 | 281 | button:focus:not(:focus-visible) { 282 | outline: 0; 283 | } 284 | 285 | input, 286 | button, 287 | select, 288 | optgroup, 289 | textarea { 290 | margin: 0; 291 | font-family: inherit; 292 | font-size: inherit; 293 | line-height: inherit; 294 | } 295 | 296 | button, 297 | select { 298 | text-transform: none; 299 | } 300 | 301 | [role=button] { 302 | cursor: pointer; 303 | } 304 | 305 | select { 306 | word-wrap: normal; 307 | } 308 | select:disabled { 309 | opacity: 1; 310 | } 311 | 312 | [list]::-webkit-calendar-picker-indicator { 313 | display: none; 314 | } 315 | 316 | button, 317 | [type=button], 318 | [type=reset], 319 | [type=submit] { 320 | -webkit-appearance: button; 321 | } 322 | button:not(:disabled), 323 | [type=button]:not(:disabled), 324 | [type=reset]:not(:disabled), 325 | [type=submit]:not(:disabled) { 326 | cursor: pointer; 327 | } 328 | 329 | ::-moz-focus-inner { 330 | padding: 0; 331 | border-style: none; 332 | } 333 | 334 | textarea { 335 | resize: vertical; 336 | } 337 | 338 | fieldset { 339 | min-width: 0; 340 | padding: 0; 341 | margin: 0; 342 | border: 0; 343 | } 344 | 345 | legend { 346 | float: right; 347 | width: 100%; 348 | padding: 0; 349 | margin-bottom: 0.5rem; 350 | font-size: calc(1.275rem + 0.3vw); 351 | line-height: inherit; 352 | } 353 | @media (min-width: 1200px) { 354 | legend { 355 | font-size: 1.5rem; 356 | } 357 | } 358 | legend + * { 359 | clear: right; 360 | } 361 | 362 | ::-webkit-datetime-edit-fields-wrapper, 363 | ::-webkit-datetime-edit-text, 364 | ::-webkit-datetime-edit-minute, 365 | ::-webkit-datetime-edit-hour-field, 366 | ::-webkit-datetime-edit-day-field, 367 | ::-webkit-datetime-edit-month-field, 368 | ::-webkit-datetime-edit-year-field { 369 | padding: 0; 370 | } 371 | 372 | ::-webkit-inner-spin-button { 373 | height: auto; 374 | } 375 | 376 | [type=search] { 377 | outline-offset: -2px; 378 | -webkit-appearance: textfield; 379 | } 380 | 381 | [type="tel"], 382 | [type="url"], 383 | [type="email"], 384 | [type="number"] { 385 | direction: ltr; 386 | } 387 | ::-webkit-search-decoration { 388 | -webkit-appearance: none; 389 | } 390 | 391 | ::-webkit-color-swatch-wrapper { 392 | padding: 0; 393 | } 394 | 395 | ::file-selector-button { 396 | font: inherit; 397 | } 398 | 399 | ::-webkit-file-upload-button { 400 | font: inherit; 401 | -webkit-appearance: button; 402 | } 403 | 404 | output { 405 | display: inline-block; 406 | } 407 | 408 | iframe { 409 | border: 0; 410 | } 411 | 412 | summary { 413 | display: list-item; 414 | cursor: pointer; 415 | } 416 | 417 | progress { 418 | vertical-align: baseline; 419 | } 420 | 421 | [hidden] { 422 | display: none !important; 423 | } 424 | /*# sourceMappingURL=bootstrap-reboot.rtl.css.map */ -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v5.1.0 (https://getbootstrap.com/) 3 | * Copyright 2011-2021 The Bootstrap Authors 4 | * Copyright 2011-2021 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-right:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-right:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:right}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:right;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:right}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}[type=email],[type=number],[type=tel],[type=url]{direction:ltr}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important} 8 | /*# sourceMappingURL=bootstrap-reboot.rtl.min.css.map */ -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) .NET Foundation. All rights reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | these files except in compliance with the License. You may obtain a copy of the 5 | License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software distributed 10 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | specific language governing permissions and limitations under the License. 13 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js: -------------------------------------------------------------------------------- 1 | // Unobtrusive validation support library for jQuery and jQuery Validate 2 | // Copyright (c) .NET Foundation. All rights reserved. 3 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 4 | // @version v3.2.11 5 | !function(a){"function"==typeof define&&define.amd?define("jquery.validate.unobtrusive",["jquery-validation"],a):"object"==typeof module&&module.exports?module.exports=a(require("jquery-validation")):jQuery.validator.unobtrusive=a(jQuery)}(function(a){function e(a,e,n){a.rules[e]=n,a.message&&(a.messages[e]=a.message)}function n(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function t(a){return a.replace(/([!"#$%&'()*+,.\/:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function r(a){return a.substr(0,a.lastIndexOf(".")+1)}function i(a,e){return 0===a.indexOf("*.")&&(a=a.replace("*.",e)),a}function o(e,n){var r=a(this).find("[data-valmsg-for='"+t(n[0].name)+"']"),i=r.attr("data-valmsg-replace"),o=i?a.parseJSON(i)!==!1:null;r.removeClass("field-validation-valid").addClass("field-validation-error"),e.data("unobtrusiveContainer",r),o?(r.empty(),e.removeClass("input-validation-error").appendTo(r)):e.hide()}function d(e,n){var t=a(this).find("[data-valmsg-summary=true]"),r=t.find("ul");r&&r.length&&n.errorList.length&&(r.empty(),t.addClass("validation-summary-errors").removeClass("validation-summary-valid"),a.each(n.errorList,function(){a("
  • ").html(this.message).appendTo(r)}))}function s(e){var n=e.data("unobtrusiveContainer");if(n){var t=n.attr("data-valmsg-replace"),r=t?a.parseJSON(t):null;n.addClass("field-validation-valid").removeClass("field-validation-error"),e.removeData("unobtrusiveContainer"),r&&n.empty()}}function l(e){var n=a(this),t="__jquery_unobtrusive_validation_form_reset";if(!n.data(t)){n.data(t,!0);try{n.data("validator").resetForm()}finally{n.removeData(t)}n.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors"),n.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}}function u(e){var n=a(e),t=n.data(v),r=a.proxy(l,e),i=f.unobtrusive.options||{},u=function(n,t){var r=i[n];r&&a.isFunction(r)&&r.apply(e,t)};return t||(t={options:{errorClass:i.errorClass||"input-validation-error",errorElement:i.errorElement||"span",errorPlacement:function(){o.apply(e,arguments),u("errorPlacement",arguments)},invalidHandler:function(){d.apply(e,arguments),u("invalidHandler",arguments)},messages:{},rules:{},success:function(){s.apply(e,arguments),u("success",arguments)}},attachValidation:function(){n.off("reset."+v,r).on("reset."+v,r).validate(this.options)},validate:function(){return n.validate(),n.valid()}},n.data(v,t)),t}var m,f=a.validator,v="unobtrusiveValidation";return f.unobtrusive={adapters:[],parseElement:function(e,n){var t,r,i,o=a(e),d=o.parents("form")[0];d&&(t=u(d),t.options.rules[e.name]=r={},t.options.messages[e.name]=i={},a.each(this.adapters,function(){var n="data-val-"+this.name,t=o.attr(n),s={};void 0!==t&&(n+="-",a.each(this.params,function(){s[this]=o.attr(n+this)}),this.adapt({element:e,form:d,message:t,params:s,rules:r,messages:i}))}),a.extend(r,{__dummy__:!0}),n||t.attachValidation())},parse:function(e){var n=a(e),t=n.parents().addBack().filter("form").add(n.find("form")).has("[data-val=true]");n.find("[data-val=true]").each(function(){f.unobtrusive.parseElement(this,!0)}),t.each(function(){var a=u(this);a&&a.attachValidation()})}},m=f.unobtrusive.adapters,m.add=function(a,e,n){return n||(n=e,e=[]),this.push({name:a,params:e,adapt:n}),this},m.addBool=function(a,n){return this.add(a,function(t){e(t,n||a,!0)})},m.addMinMax=function(a,n,t,r,i,o){return this.add(a,[i||"min",o||"max"],function(a){var i=a.params.min,o=a.params.max;i&&o?e(a,r,[i,o]):i?e(a,n,i):o&&e(a,t,o)})},m.addSingleVal=function(a,n,t){return this.add(a,[n||"val"],function(r){e(r,t||a,r.params[n])})},f.addMethod("__dummy__",function(a,e,n){return!0}),f.addMethod("regex",function(a,e,n){var t;return!!this.optional(e)||(t=new RegExp(n).exec(a),t&&0===t.index&&t[0].length===a.length)}),f.addMethod("nonalphamin",function(a,e,n){var t;return n&&(t=a.match(/\W/g),t=t&&t.length>=n),t}),f.methods.extension?(m.addSingleVal("accept","mimtype"),m.addSingleVal("extension","extension")):m.addSingleVal("extension","extension","accept"),m.addSingleVal("regex","pattern"),m.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"),m.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range"),m.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength"),m.add("equalto",["other"],function(n){var o=r(n.element.name),d=n.params.other,s=i(d,o),l=a(n.form).find(":input").filter("[name='"+t(s)+"']")[0];e(n,"equalTo",l)}),m.add("required",function(a){"INPUT"===a.element.tagName.toUpperCase()&&"CHECKBOX"===a.element.type.toUpperCase()||e(a,"required",!0)}),m.add("remote",["url","type","additionalfields"],function(o){var d={url:o.params.url,type:o.params.type||"GET",data:{}},s=r(o.element.name);a.each(n(o.params.additionalfields||o.element.name),function(e,n){var r=i(n,s);d.data[r]=function(){var e=a(o.form).find(":input").filter("[name='"+t(r)+"']");return e.is(":checkbox")?e.filter(":checked").val()||e.filter(":hidden").val()||"":e.is(":radio")?e.filter(":checked").val()||"":e.val()}}),e(o,"remote",d)}),m.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&e(a,"minlength",a.params.min),a.params.nonalphamin&&e(a,"nonalphamin",a.params.nonalphamin),a.params.regex&&e(a,"regex",a.params.regex)}),m.add("fileextensions",["extensions"],function(a){e(a,"extension",a.params.extensions)}),a(function(){f.unobtrusive.parse(document)}),f.unobtrusive}); 6 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/wwwroot/lib/jquery-validation/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright Jörn Zaefferer 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /parts/5-performance-tips/ContosoPizza/wwwroot/lib/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright JS Foundation and other contributors, https://js.foundation/ 2 | 3 | This software consists of voluntary contributions made by many 4 | individuals. For exact contribution history, see the revision history 5 | available at https://github.com/jquery/jquery 6 | 7 | The following license applies to all parts of this software except as 8 | documented below: 9 | 10 | ==== 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining 13 | a copy of this software and associated documentation files (the 14 | "Software"), to deal in the Software without restriction, including 15 | without limitation the rights to use, copy, modify, merge, publish, 16 | distribute, sublicense, and/or sell copies of the Software, and to 17 | permit persons to whom the Software is furnished to do so, subject to 18 | the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | ==== 32 | 33 | All files located in the node_modules and external directories are 34 | externally maintained libraries used by this software which have their 35 | own licenses; we recommend you read them, as their terms may differ from 36 | the terms above. 37 | --------------------------------------------------------------------------------