Merge branch 'main' into tw-bootstrap

This commit is contained in:
James Montemagno
2023-09-14 13:18:09 -07:00
committed by GitHub
32 changed files with 810 additions and 184 deletions

View File

@@ -1,82 +0,0 @@
#-------------------------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
FROM mcr.microsoft.com/dotnet/sdk:7.0
# This Dockerfile adds a non-root user with sudo access. Use the "remoteUser"
# property in devcontainer.json to use it. On Linux, the container user's GID/UIDs
# will be updated to match your local UID/GID (when using the dockerFile property).
# See https://aka.ms/vscode-remote/containers/non-root-user for details.
ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=$USER_UID
# [Optional] Version of Node.js to install.
ARG INSTALL_NODE="false"
ARG NODE_VERSION="lts/*"
ENV NVM_DIR=/usr/local/share/nvm
# [Optional] Install the Azure CLI
ARG INSTALL_AZURE_CLI="false"
# Configure apt and install packages
RUN apt-get update \
&& export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \
#
# Verify git, process tools, lsb-release (common in install instructions for CLIs) installed
&& apt-get -y install git openssh-client less iproute2 procps apt-transport-https gnupg2 curl lsb-release \
#
# Create a non-root user to use if preferred - see https://aka.ms/vscode-remote/containers/non-root-user.
&& groupadd --gid $USER_GID $USERNAME \
&& useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
# [Optional] Add sudo support for the non-root user
&& apt-get install -y sudo \
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME\
&& chmod 0440 /etc/sudoers.d/$USERNAME \
#
# [Optional] Install Node.js for ASP.NET Core Web Applicationss
&& if [ "$INSTALL_NODE" = "true" ]; then \
#
# Install nvm and Node
mkdir -p ${NVM_DIR} \
&& curl -so- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash 2>&1 \
&& chown -R ${USER_UID}:${USER_GID} ${NVM_DIR} \
&& /bin/bash -c "source $NVM_DIR/nvm.sh \
&& nvm alias default ${NODE_VERSION}" 2>&1 \
&& echo '[ -s "$NVM_DIR/nvm.sh" ] && \\. "$NVM_DIR/nvm.sh" && [ -s "$NVM_DIR/bash_completion" ] && \\. "$NVM_DIR/bash_completion"' \
| tee -a /home/${USERNAME}/.bashrc /home/${USERNAME}/.zshrc >> /root/.zshrc \
&& echo "if [ \"\$(stat -c '%U' ${NVM_DIR})\" != \"${USERNAME}\" ]; then sudo chown -R ${USER_UID}:root ${NVM_DIR}; fi" \
| tee -a /root/.bashrc /root/.zshrc /home/${USERNAME}/.bashrc >> /home/${USERNAME}/.zshrc \
&& chown ${USER_UID}:${USER_GID} /home/${USERNAME}/.bashrc /home/${USERNAME}/.zshrc \
&& chown -R ${USER_UID}:root ${NVM_DIR} \
#
# Install yarn
&& curl -sS https://dl.yarnpkg.com/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/pubkey.gpg | apt-key add - 2>/dev/null \
&& echo "deb https://dl.yarnpkg.com/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
&& apt-get update \
&& apt-get -y install --no-install-recommends yarn; \
fi \
#
# [Optional] Install the Azure CLI
&& if [ "$INSTALL_AZURE_CLI" = "true" ]; then \
echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ $(lsb_release -cs) main" > /etc/apt/sources.list.d/azure-cli.list \
&& curl -sL https://packages.microsoft.com/keys/microsoft.asc | apt-key add - 2>/dev/null \
&& apt-get update \
&& apt-get install -y azure-cli; \
fi \
#
# Install EF Core dotnet tool
&& dotnet tool install dotnet-ef --tool-path /home/$USERNAME/.dotnet/tools \
&& chown -R $USERNAME /home/$USERNAME/.dotnet \
#
# Clean up
&& apt-get autoremove -y \
&& apt-get clean -y \
&& rm -rf /var/lib/apt/lists/*
# Set PATH for dotnet tools
ENV PATH "$PATH:/home/$USERNAME/.dotnet/tools"

View File

@@ -1,47 +1,29 @@
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.112.0/containers/dotnetcore-3.1
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/dotnet
{
"name": "eShopOnWeb",
"build": {
"dockerfile": "Dockerfile",
"args": {
"USERNAME": "vscode",
"INSTALL_NODE": "false",
"NODE_VERSION": "lts/*",
"INSTALL_AZURE_CLI": "false"
}
},
"image": "mcr.microsoft.com/devcontainers/dotnet:0-7.0",
// Comment out to connect as root user. See https://aka.ms/vscode-remote/containers/non-root.
// make sure this is the same as USERNAME above
"remoteUser": "vscode",
"runArgs": [
"-v",
"/var/run/docker.sock:/var/run/docker.sock"
],
// Set *default* container specific settings.json values on container create.
"settings": {
"terminal.integrated.profiles.linux": {
"bash": {
"path": "bash",
"icon": "terminal-bash"
},
},
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"ms-dotnettools.csharp",
"formulahendry.dotnet-test-explorer",
"ms-vscode.vscode-node-azure-pack",
"ms-kubernetes-tools.vscode-kubernetes-tools",
"redhat.vscode-yaml"
]
}
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"ms-dotnettools.csharp",
"formulahendry.dotnet-test-explorer",
"ms-vscode.vscode-node-azure-pack",
"ms-kubernetes-tools.vscode-kubernetes-tools",
"redhat.vscode-yaml"
],
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [5000, 5001],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "dotnet dev-certs https --trust"
// [Optional] To reuse of your local HTTPS dev cert, first export it locally using this command:
// * Windows PowerShell:
// dotnet dev-certs https --trust; dotnet dev-certs https -ep "$env:USERPROFILE/.aspnet/https/aspnetapp.pfx" -p "SecurePwdGoesHere"
@@ -51,14 +33,11 @@
// Next, after running the command above, uncomment lines in the 'mounts' and 'remoteEnv' lines below,
// and open / rebuild the container so the settings take effect.
//
"mounts": [
// "source=${env:HOME}${env:USERPROFILE}/.aspnet/https,target=/home/vscode/.aspnet/https,type=bind"
],
"remoteEnv": {
// "ASPNETCORE_Kestrel__Certificates__Default__Password": "SecurePwdGoesHere",
// "ASPNETCORE_Kestrel__Certificates__Default__Path": "/home/vscode/.aspnet/https/aspnetapp.pfx",
}
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "dotnet restore"
// "mounts": [
// // "source=${env:HOME}${env:USERPROFILE}/.aspnet/https,target=/home/vscode/.aspnet/https,type=bind"
// ],
// "remoteEnv": {
// // "ASPNETCORE_Kestrel__Certificates__Default__Password": "SecurePwdGoesHere",
// // "ASPNETCORE_Kestrel__Certificates__Default__Path": "/home/vscode/.aspnet/https/aspnetapp.pfx",
// },
}

View File

@@ -0,0 +1,36 @@
# Dev container
This project includes a [dev container](https://containers.dev/), which lets you use a container as a full-featured dev environment.
You can use the dev container configuration in this folder to build and run the app without needing to install any of its tools locally! You can use it in [GitHub Codespaces](https://github.com/features/codespaces) or the [VS Code Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers).
## GitHub Codespaces
Follow these steps to open this sample in a Codespace:
1. Click the **Code** drop-down menu at the top of https://github.com/dotnet-architecture/eShopOnWeb.
1. Click on the **Codespaces** tab.
1. Click **Create codespace on main** .
For more info, check out the [GitHub documentation](https://docs.github.com/en/free-pro-team@latest/github/developing-online-with-codespaces/creating-a-codespace#creating-a-codespace).
## VS Code Dev Containers
If you already have VS Code and Docker installed, you can click [here](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/dotnet-architecture/eShopOnWeb) to get started. This will cause VS Code to automatically install the Dev Containers extension if needed, clone the source code into a container volume, and spin up a dev container for use.
You can also follow these steps to open this sample in a container using the VS Code Dev Containers extension:
1. If this is your first time using a development container, please ensure your system meets the pre-reqs (i.e. have Docker installed) in the [getting started steps](https://aka.ms/vscode-remote/containers/getting-started).
2. Open a locally cloned copy of the code:
- Clone this repository to your local filesystem.
- Press <kbd>F1</kbd> and select the **Dev Containers: Open Folder in Container...** command.
- Select the cloned copy of this folder, wait for the container to start, and try things out!
You can learn more in the [Dev Containers documentation](https://code.visualstudio.com/docs/devcontainers/containers).
## Tips and tricks
* Since the dev container is Linux-based, you won't be able to use LocalDB. Add ` "UseOnlyInMemoryDatabase": true,` to the [appsettings.json](../src/Web/appsettings.json) file (there's additional context on this [in the app's readme](../README.md#configuring-the-sample-to-use-sql-server)).
* If you get a `502 bad gateway` error, you may need to set your port to the https protocol. You can do this by opening the Ports view in VS Code (**Ports: Focus on Ports View**), right-clicking on the port you're using, select **Change Port Protocol**, and set **https**.
* If you are working with the same repository folder in a container and Windows, you'll want consistent line endings (otherwise you may see hundreds of changes in the SCM view). The `.gitattributes` file in the root of this repo disables line ending conversion and should prevent this. See [tips and tricks](https://code.visualstudio.com/docs/devcontainers/tips-and-tricks#_resolving-git-line-ending-issues-in-containers-resulting-in-many-modified-files) for more info.
* If you'd like to review the contents of the image used in this dev container, you can check it out in the [devcontainers/images](https://github.com/devcontainers/images/tree/main/src/dotnet) repo.

3
.gitattributes vendored Normal file
View File

@@ -0,0 +1,3 @@
* text=auto eol=lf
*.{cmd,[cC][mM][dD]} text eol=crlf
*.{bat,[bB][aA][tT]} text eol=crlf

View File

@@ -1,11 +1,11 @@
name: eShopOnWeb Rich Code Navigation
name: eShopOnWeb - Code Index
on: [push, pull_request, workflow_dispatch]
on: workflow_dispatch
jobs:
build:
runs-on: windows-2019
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
@@ -15,8 +15,10 @@ jobs:
dotnet-version: 7.0.x
- name: Build with dotnet
run: dotnet build ./eShopOnWeb.sln --configuration Release
run: dotnet build ./Everything.sln --configuration Release /bl
- uses: microsoft/RichCodeNavIndexer@v0.1
with:
repo-token: ${{ github.token }}
repo-token: ${{ github.token }}
languages: 'csharp'
environment: 'internal'

3
.gitignore vendored
View File

@@ -257,3 +257,6 @@ pub/
#Ignore marker-file used to know which docker files we have.
.eshopdocker_*
.devcontainer
.azure

View File

@@ -4,6 +4,7 @@
"formulahendry.dotnet-test-explorer",
"ms-vscode.vscode-node-azure-pack",
"ms-kubernetes-tools.vscode-kubernetes-tools",
"redhat.vscode-yaml"
"redhat.vscode-yaml",
"ms-azuretools.azure-dev"
]
}

View File

@@ -1,39 +1,40 @@
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Ardalis.ApiEndpoints" Version="4.0.1" />
<PackageVersion Include="Ardalis.GuardClauses" Version="4.0.1" />
<PackageVersion Include="Ardalis.Specification.EntityFrameworkCore" Version="6.1.0" />
<PackageVersion Include="Ardalis.Specification.EntityFrameworkCore" Version="7.0.0" />
<PackageVersion Include="Ardalis.Result" Version="7.0.0" />
<PackageVersion Include="Ardalis.Specification" Version="6.1.0" />
<PackageVersion Include="Ardalis.Specification" Version="7.0.0" />
<PackageVersion Include="Ardalis.ListStartupServices" Version="1.1.4" />
<PackageVersion Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.0" />
<PackageVersion Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.2.1" />
<PackageVersion Include="Azure.Identity" Version="1.9.0-beta.2" />
<PackageVersion Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
<PackageVersion Include="BlazorInputFile" Version="0.2.0" />
<PackageVersion Include="Blazored.LocalStorage" Version="4.3.0" />
<PackageVersion Include="BuildBundlerMinifier" Version="3.2.449" PrivateAssets="All" />
<PackageVersion Include="FluentValidation" Version="11.5.1" />
<PackageVersion Include="FluentValidation" Version="11.7.1" />
<PackageVersion Include="MediatR" Version="12.0.1" />
<PackageVersion Include="Microsoft.AspNetCore.Components.Authorization" Version="7.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="7.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.4" PrivateAssets="all" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="7.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="7.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Identity.UI" Version="7.0.4" />
<PackageVersion Include="Microsoft.AspNetCore.Components.Authorization" Version="7.0.10" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.8" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="7.0.10" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.5" PrivateAssets="all" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="7.0.5" />
<PackageVersion Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.5" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.8" />
<PackageVersion Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="7.0.8" />
<PackageVersion Include="Microsoft.AspNetCore.Identity.UI" Version="7.0.5" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
<PackageVersion Include="Microsoft.Extensions.Identity.Core" Version="7.0.4" />
<PackageVersion Include="Microsoft.Extensions.Identity.Core" Version="7.0.5" />
<PackageVersion Include="Microsoft.Extensions.Logging.Configuration" Version="7.0.0" />
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.5" />
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.6" />
<PackageVersion Include="Microsoft.Web.LibraryManager.Build" Version="2.1.175" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.4" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.4" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.4">
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.5" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.5" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageVersion>
@@ -42,13 +43,13 @@
<PackageVersion Include="System.Net.Http.Json" Version="7.0.1" />
<PackageVersion Include="System.Security.Claims" Version="4.3.0" />
<PackageVersion Include="System.Text.Json" Version="7.0.2" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.27.0" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.32.3" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageVersion Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.5.0" />
<PackageVersion Include="Swashbuckle.AspNetCore.Annotations" Version="6.5.0" />
<!-- Test -->
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="7.0.4" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="7.0.8" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
<PackageVersion Include="xunit" Version="2.4.2" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>
@@ -61,6 +62,6 @@
<PackageVersion Include="Moq" Version="4.18.4" />
<PackageVersion Include="MSTest.TestAdapter" Version="3.0.2" />
<PackageVersion Include="MSTest.TestFramework" Version="3.0.2" />
<PackageVersion Include="coverlet.collector" Version="3.2.0" />
<PackageVersion Include="coverlet.collector" Version="6.0.0" />
</ItemGroup>
</Project>

View File

@@ -41,12 +41,55 @@ The goal for this sample is to demonstrate some of the principles and patterns d
- Development Process for Azure-Hosted ASP.NET Core Apps
- Azure Hosting Recommendations for ASP.NET Core Web Apps
## Running the sample
## Running the sample using Azd template
The store's home page should look like this:
![eShopOnWeb home page screenshot](https://user-images.githubusercontent.com/782127/88414268-92d83a00-cdaa-11ea-9b4c-db67d95be039.png)
The Azure Developer CLI (`azd`) is a developer-centric command-line interface (CLI) tool for creating Azure applications.
You need to install it before running and deploying with Azure Developer CLI.
### Windows
```powershell
powershell -ex AllSigned -c "Invoke-RestMethod 'https://aka.ms/install-azd.ps1' | Invoke-Expression"
```
### Linux/MacOS
```
curl -fsSL https://aka.ms/install-azd.sh | bash
```
And you can also install with package managers, like winget, choco, and brew. For more details, you can follow the documentation: https://aka.ms/azure-dev/install.
After logging in with the following command, you will be able to use the azd cli to quickly provision and deploy the application.
```
azd auth login
```
Then, execute the `azd init` command to initialize the environment.
```
azd init -t dotnet-architecture/eShopOnWeb
```
Run `azd up` to provision all the resources to Azure and deploy the code to those resources.
```
azd up
```
According to the prompt, enter an `env name`, and select `subscription` and `location`, these are the necessary parameters when you create resources. Wait a moment for the resource deployment to complete, click the web endpoint and you will see the home page.
**Notes:**
1. Considering security, we store its related data (id, password) in the **Azure Key Vault** when we create the database, and obtain it from the Key Vault when we use it. This is different from directly deploying applications locally.
2. The resource group name created in azure portal will be **rg-{env name}**.
You can also run the sample directly locally (See below).
## Running the sample locally
Most of the site's functionality works with just the web application running. However, the site's Admin page relies on Blazor WebAssembly running in the browser, and it must communicate with the server using the site's PublicApi web application. You'll need to also run this project. You can configure Visual Studio to start multiple projects, or just go to the PublicApi folder in a terminal window and run `dotnet run` from there. After that from the Web folder you should run `dotnet run --launch-profile Web`. Now you should be able to browse to `https://localhost:5001/`. The admin part in Blazor is accessible to `https://localhost:5001/admin`
Note that if you use this approach, you'll need to stop the application manually in order to build the solution (otherwise you'll get file locking errors).
@@ -58,13 +101,12 @@ You can also run the samples in Docker (see below).
### Configuring the sample to use SQL Server
1. By default, the project uses a real database. If you want an in memory database, you can add in `appsettings.json`
1. By default, the project uses a real database. If you want an in memory database, you can add in the `appsettings.json` file in the Web folder
```json
{
"UseOnlyInMemoryDatabase": true
}
```
1. Ensure your connection strings in `appsettings.json` point to a local SQL Server instance.
@@ -98,6 +140,14 @@ You can also run the samples in Docker (see below).
dotnet ef migrations add InitialIdentityModel --context appidentitydbcontext -p ../Infrastructure/Infrastructure.csproj -s Web.csproj -o Identity/Migrations
```
## Running the sample in the dev container
This project includes a `.devcontainer` folder with a [dev container configuration](https://containers.dev/), which lets you use a container as a full-featured dev environment.
You can use the dev container to build and run the app without needing to install any of its tools locally! You can work in GitHub Codespaces or the VS Code Dev Containers extension.
Learn more about using the dev container in its [readme](/.devcontainer/devcontainerreadme.md).
## Running the sample using Docker
You can run the Web sample by running these commands from the root folder (where the .sln file is located):

8
azure.yaml Normal file
View File

@@ -0,0 +1,8 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/wbreza/azure-dev/main/schemas/v1.0/azure.yaml.json
name: eShopOnWeb
services:
web:
project: ./src/Web
language: csharp
host: appservice

135
infra/abbreviations.json Normal file
View File

@@ -0,0 +1,135 @@
{
"analysisServicesServers": "as",
"apiManagementService": "apim-",
"appConfigurationConfigurationStores": "appcs-",
"appManagedEnvironments": "cae-",
"appContainerApps": "ca-",
"authorizationPolicyDefinitions": "policy-",
"automationAutomationAccounts": "aa-",
"blueprintBlueprints": "bp-",
"blueprintBlueprintsArtifacts": "bpa-",
"cacheRedis": "redis-",
"cdnProfiles": "cdnp-",
"cdnProfilesEndpoints": "cdne-",
"cognitiveServicesAccounts": "cog-",
"cognitiveServicesFormRecognizer": "cog-fr-",
"cognitiveServicesTextAnalytics": "cog-ta-",
"computeAvailabilitySets": "avail-",
"computeCloudServices": "cld-",
"computeDiskEncryptionSets": "des",
"computeDisks": "disk",
"computeDisksOs": "osdisk",
"computeGalleries": "gal",
"computeSnapshots": "snap-",
"computeVirtualMachines": "vm",
"computeVirtualMachineScaleSets": "vmss-",
"containerInstanceContainerGroups": "ci",
"containerRegistryRegistries": "cr",
"containerServiceManagedClusters": "aks-",
"databricksWorkspaces": "dbw-",
"dataFactoryFactories": "adf-",
"dataLakeAnalyticsAccounts": "dla",
"dataLakeStoreAccounts": "dls",
"dataMigrationServices": "dms-",
"dBforMySQLServers": "mysql-",
"dBforPostgreSQLServers": "psql-",
"devicesIotHubs": "iot-",
"devicesProvisioningServices": "provs-",
"devicesProvisioningServicesCertificates": "pcert-",
"documentDBDatabaseAccounts": "cosmos-",
"eventGridDomains": "evgd-",
"eventGridDomainsTopics": "evgt-",
"eventGridEventSubscriptions": "evgs-",
"eventHubNamespaces": "evhns-",
"eventHubNamespacesEventHubs": "evh-",
"hdInsightClustersHadoop": "hadoop-",
"hdInsightClustersHbase": "hbase-",
"hdInsightClustersKafka": "kafka-",
"hdInsightClustersMl": "mls-",
"hdInsightClustersSpark": "spark-",
"hdInsightClustersStorm": "storm-",
"hybridComputeMachines": "arcs-",
"insightsActionGroups": "ag-",
"insightsComponents": "appi-",
"keyVaultVaults": "kv-",
"kubernetesConnectedClusters": "arck",
"kustoClusters": "dec",
"kustoClustersDatabases": "dedb",
"logicIntegrationAccounts": "ia-",
"logicWorkflows": "logic-",
"machineLearningServicesWorkspaces": "mlw-",
"managedIdentityUserAssignedIdentities": "id-",
"managementManagementGroups": "mg-",
"migrateAssessmentProjects": "migr-",
"networkApplicationGateways": "agw-",
"networkApplicationSecurityGroups": "asg-",
"networkAzureFirewalls": "afw-",
"networkBastionHosts": "bas-",
"networkConnections": "con-",
"networkDnsZones": "dnsz-",
"networkExpressRouteCircuits": "erc-",
"networkFirewallPolicies": "afwp-",
"networkFirewallPoliciesWebApplication": "waf",
"networkFirewallPoliciesRuleGroups": "wafrg",
"networkFrontDoors": "fd-",
"networkFrontdoorWebApplicationFirewallPolicies": "fdfp-",
"networkLoadBalancersExternal": "lbe-",
"networkLoadBalancersInternal": "lbi-",
"networkLoadBalancersInboundNatRules": "rule-",
"networkLocalNetworkGateways": "lgw-",
"networkNatGateways": "ng-",
"networkNetworkInterfaces": "nic-",
"networkNetworkSecurityGroups": "nsg-",
"networkNetworkSecurityGroupsSecurityRules": "nsgsr-",
"networkNetworkWatchers": "nw-",
"networkPrivateDnsZones": "pdnsz-",
"networkPrivateLinkServices": "pl-",
"networkPublicIPAddresses": "pip-",
"networkPublicIPPrefixes": "ippre-",
"networkRouteFilters": "rf-",
"networkRouteTables": "rt-",
"networkRouteTablesRoutes": "udr-",
"networkTrafficManagerProfiles": "traf-",
"networkVirtualNetworkGateways": "vgw-",
"networkVirtualNetworks": "vnet-",
"networkVirtualNetworksSubnets": "snet-",
"networkVirtualNetworksVirtualNetworkPeerings": "peer-",
"networkVirtualWans": "vwan-",
"networkVpnGateways": "vpng-",
"networkVpnGatewaysVpnConnections": "vcn-",
"networkVpnGatewaysVpnSites": "vst-",
"notificationHubsNamespaces": "ntfns-",
"notificationHubsNamespacesNotificationHubs": "ntf-",
"operationalInsightsWorkspaces": "log-",
"portalDashboards": "dash-",
"powerBIDedicatedCapacities": "pbi-",
"purviewAccounts": "pview-",
"recoveryServicesVaults": "rsv-",
"resourcesResourceGroups": "rg-",
"searchSearchServices": "srch-",
"serviceBusNamespaces": "sb-",
"serviceBusNamespacesQueues": "sbq-",
"serviceBusNamespacesTopics": "sbt-",
"serviceEndPointPolicies": "se-",
"serviceFabricClusters": "sf-",
"signalRServiceSignalR": "sigr",
"sqlManagedInstances": "sqlmi-",
"sqlServers": "sql-",
"sqlServersDataWarehouse": "sqldw-",
"sqlServersDatabases": "sqldb-",
"sqlServersDatabasesStretch": "sqlstrdb-",
"storageStorageAccounts": "st",
"storageStorageAccountsVm": "stvm",
"storSimpleManagers": "ssimp",
"streamAnalyticsCluster": "asa-",
"synapseWorkspaces": "syn",
"synapseWorkspacesAnalyticsWorkspaces": "synw",
"synapseWorkspacesSqlPoolsDedicated": "syndp",
"synapseWorkspacesSqlPoolsSpark": "synsp",
"timeSeriesInsightsEnvironments": "tsi-",
"webServerFarms": "plan-",
"webSitesAppService": "app-",
"webSitesAppServiceEnvironment": "ase-",
"webSitesFunctions": "func-",
"webStaticSites": "stapp-"
}

View File

@@ -0,0 +1,129 @@
param name string
param location string = resourceGroup().location
param tags object = {}
param appUser string = 'appUser'
param databaseName string
param keyVaultName string
param sqlAdmin string = 'sqlAdmin'
param connectionStringKey string = 'AZURE-SQL-CONNECTION-STRING'
@secure()
param sqlAdminPassword string
@secure()
param appUserPassword string
resource sqlServer 'Microsoft.Sql/servers@2022-05-01-preview' = {
name: name
location: location
tags: tags
properties: {
version: '12.0'
minimalTlsVersion: '1.2'
publicNetworkAccess: 'Enabled'
administratorLogin: sqlAdmin
administratorLoginPassword: sqlAdminPassword
}
resource database 'databases' = {
name: databaseName
location: location
}
resource firewall 'firewallRules' = {
name: 'Azure Services'
properties: {
// Allow all clients
// Note: range [0.0.0.0-0.0.0.0] means "allow all Azure-hosted clients only".
// This is not sufficient, because we also want to allow direct access from developer machine, for debugging purposes.
startIpAddress: '0.0.0.1'
endIpAddress: '255.255.255.254'
}
}
}
resource sqlDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = {
name: '${name}-deployment-script'
location: location
kind: 'AzureCLI'
properties: {
azCliVersion: '2.37.0'
retentionInterval: 'PT1H' // Retain the script resource for 1 hour after it ends running
timeout: 'PT5M' // Five minutes
cleanupPreference: 'OnSuccess'
environmentVariables: [
{
name: 'APPUSERNAME'
value: appUser
}
{
name: 'APPUSERPASSWORD'
secureValue: appUserPassword
}
{
name: 'DBNAME'
value: databaseName
}
{
name: 'DBSERVER'
value: sqlServer.properties.fullyQualifiedDomainName
}
{
name: 'SQLCMDPASSWORD'
secureValue: sqlAdminPassword
}
{
name: 'SQLADMIN'
value: sqlAdmin
}
]
scriptContent: '''
wget https://github.com/microsoft/go-sqlcmd/releases/download/v0.8.1/sqlcmd-v0.8.1-linux-x64.tar.bz2
tar x -f sqlcmd-v0.8.1-linux-x64.tar.bz2 -C .
cat <<SCRIPT_END > ./initDb.sql
drop user ${APPUSERNAME}
go
create user ${APPUSERNAME} with password = '${APPUSERPASSWORD}'
go
alter role db_owner add member ${APPUSERNAME}
go
SCRIPT_END
./sqlcmd -S ${DBSERVER} -d ${DBNAME} -U ${SQLADMIN} -i ./initDb.sql
'''
}
}
resource sqlAdminPasswordSecret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = {
parent: keyVault
name: 'sqlAdminPassword'
properties: {
value: sqlAdminPassword
}
}
resource appUserPasswordSecret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = {
parent: keyVault
name: 'appUserPassword'
properties: {
value: appUserPassword
}
}
resource sqlAzureConnectionStringSercret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = {
parent: keyVault
name: connectionStringKey
properties: {
value: '${connectionString}; Password=${appUserPassword}'
}
}
resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = {
name: keyVaultName
}
var connectionString = 'Server=${sqlServer.properties.fullyQualifiedDomainName}; Database=${sqlServer::database.name}; User=${appUser}'
output connectionStringKey string = connectionStringKey
output databaseName string = sqlServer::database.name

View File

@@ -0,0 +1,101 @@
param name string
param location string = resourceGroup().location
param tags object = {}
// Reference Properties
param applicationInsightsName string = ''
param appServicePlanId string
param keyVaultName string = ''
param managedIdentity bool = !empty(keyVaultName)
// Runtime Properties
@allowed([
'dotnet', 'dotnetcore', 'dotnet-isolated', 'node', 'python', 'java', 'powershell', 'custom'
])
param runtimeName string
param runtimeNameAndVersion string = '${runtimeName}|${runtimeVersion}'
param runtimeVersion string
// Microsoft.Web/sites Properties
param kind string = 'app,linux'
// Microsoft.Web/sites/config
param allowedOrigins array = []
param alwaysOn bool = true
param appCommandLine string = ''
param appSettings object = {}
param clientAffinityEnabled bool = false
param enableOryxBuild bool = contains(kind, 'linux')
param functionAppScaleLimit int = -1
param linuxFxVersion string = runtimeNameAndVersion
param minimumElasticInstanceCount int = -1
param numberOfWorkers int = -1
param scmDoBuildDuringDeployment bool = false
param use32BitWorkerProcess bool = false
param ftpsState string = 'FtpsOnly'
param healthCheckPath string = ''
resource appService 'Microsoft.Web/sites@2022-03-01' = {
name: name
location: location
tags: tags
kind: kind
properties: {
serverFarmId: appServicePlanId
siteConfig: {
linuxFxVersion: linuxFxVersion
alwaysOn: alwaysOn
ftpsState: ftpsState
minTlsVersion: '1.2'
appCommandLine: appCommandLine
numberOfWorkers: numberOfWorkers != -1 ? numberOfWorkers : null
minimumElasticInstanceCount: minimumElasticInstanceCount != -1 ? minimumElasticInstanceCount : null
use32BitWorkerProcess: use32BitWorkerProcess
functionAppScaleLimit: functionAppScaleLimit != -1 ? functionAppScaleLimit : null
healthCheckPath: healthCheckPath
cors: {
allowedOrigins: union([ 'https://portal.azure.com', 'https://ms.portal.azure.com' ], allowedOrigins)
}
}
clientAffinityEnabled: clientAffinityEnabled
httpsOnly: true
}
identity: { type: managedIdentity ? 'SystemAssigned' : 'None' }
resource configAppSettings 'config' = {
name: 'appsettings'
properties: union(appSettings,
{
SCM_DO_BUILD_DURING_DEPLOYMENT: string(scmDoBuildDuringDeployment)
ENABLE_ORYX_BUILD: string(enableOryxBuild)
},
!empty(applicationInsightsName) ? { APPLICATIONINSIGHTS_CONNECTION_STRING: applicationInsights.properties.ConnectionString } : {},
!empty(keyVaultName) ? { AZURE_KEY_VAULT_ENDPOINT: keyVault.properties.vaultUri } : {})
}
resource configLogs 'config' = {
name: 'logs'
properties: {
applicationLogs: { fileSystem: { level: 'Verbose' } }
detailedErrorMessages: { enabled: true }
failedRequestsTracing: { enabled: true }
httpLogs: { fileSystem: { enabled: true, retentionInDays: 1, retentionInMb: 35 } }
}
dependsOn: [
configAppSettings
]
}
}
resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = if (!(empty(keyVaultName))) {
name: keyVaultName
}
resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = if (!empty(applicationInsightsName)) {
name: applicationInsightsName
}
output identityPrincipalId string = managedIdentity ? appService.identity.principalId : ''
output name string = appService.name
output uri string = 'https://${appService.properties.defaultHostName}'

View File

@@ -0,0 +1,20 @@
param name string
param location string = resourceGroup().location
param tags object = {}
param kind string = ''
param reserved bool = true
param sku object
resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = {
name: name
location: location
tags: tags
sku: sku
kind: kind
properties: {
reserved: reserved
}
}
output id string = appServicePlan.id

View File

@@ -0,0 +1,21 @@
param name string = 'add'
param keyVaultName string
param permissions object = { secrets: [ 'get', 'list' ] }
param principalId string
resource keyVaultAccessPolicies 'Microsoft.KeyVault/vaults/accessPolicies@2022-07-01' = {
parent: keyVault
name: name
properties: {
accessPolicies: [ {
objectId: principalId
tenantId: subscription().tenantId
permissions: permissions
} ]
}
}
resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = {
name: keyVaultName
}

View File

@@ -0,0 +1,25 @@
param name string
param location string = resourceGroup().location
param tags object = {}
param principalId string = ''
resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = {
name: name
location: location
tags: tags
properties: {
tenantId: subscription().tenantId
sku: { family: 'A', name: 'standard' }
accessPolicies: !empty(principalId) ? [
{
objectId: principalId
permissions: { secrets: [ 'get', 'list' ] }
tenantId: subscription().tenantId
}
] : []
}
}
output endpoint string = keyVault.properties.vaultUri
output name string = keyVault.name

144
infra/main.bicep Normal file
View File

@@ -0,0 +1,144 @@
targetScope = 'subscription'
@minLength(1)
@maxLength(64)
@description('Name of the the environment which is used to generate a short unique hash used in all resources.')
param environmentName string
@minLength(1)
@description('Primary location for all resources')
param location string
// Optional parameters to override the default azd resource naming conventions. Update the main.parameters.json file to provide values. e.g.,:
// "resourceGroupName": {
// "value": "myGroupName"
// }
param resourceGroupName string = ''
param webServiceName string = ''
param catalogDatabaseName string = 'catalogDatabase'
param catalogDatabaseServerName string = ''
param identityDatabaseName string = 'identityDatabase'
param identityDatabaseServerName string = ''
param appServicePlanName string = ''
param keyVaultName string = ''
@description('Id of the user or app to assign application roles')
param principalId string = ''
@secure()
@description('SQL Server administrator password')
param sqlAdminPassword string
@secure()
@description('Application user password')
param appUserPassword string
var abbrs = loadJsonContent('./abbreviations.json')
var resourceToken = toLower(uniqueString(subscription().id, environmentName, location))
var tags = { 'azd-env-name': environmentName }
// Organize resources in a resource group
resource rg 'Microsoft.Resources/resourceGroups@2021-04-01' = {
name: !empty(resourceGroupName) ? resourceGroupName : '${abbrs.resourcesResourceGroups}${environmentName}'
location: location
tags: tags
}
// The application frontend
module web './core/host/appservice.bicep' = {
name: 'web'
scope: rg
params: {
name: !empty(webServiceName) ? webServiceName : '${abbrs.webSitesAppService}web-${resourceToken}'
location: location
appServicePlanId: appServicePlan.outputs.id
keyVaultName: keyVault.outputs.name
runtimeName: 'dotnetcore'
runtimeVersion: '7.0'
tags: union(tags, { 'azd-service-name': 'web' })
appSettings: {
AZURE_SQL_CATALOG_CONNECTION_STRING_KEY: 'AZURE-SQL-CATALOG-CONNECTION-STRING'
AZURE_SQL_IDENTITY_CONNECTION_STRING_KEY: 'AZURE-SQL-IDENTITY-CONNECTION-STRING'
AZURE_KEY_VAULT_ENDPOINT: keyVault.outputs.endpoint
}
}
}
module apiKeyVaultAccess './core/security/keyvault-access.bicep' = {
name: 'api-keyvault-access'
scope: rg
params: {
keyVaultName: keyVault.outputs.name
principalId: web.outputs.identityPrincipalId
}
}
// The application database: Catalog
module catalogDb './core/database/sqlserver/sqlserver.bicep' = {
name: 'sql-catalog'
scope: rg
params: {
name: !empty(catalogDatabaseServerName) ? catalogDatabaseServerName : '${abbrs.sqlServers}catalog-${resourceToken}'
databaseName: catalogDatabaseName
location: location
tags: tags
sqlAdminPassword: sqlAdminPassword
appUserPassword: appUserPassword
keyVaultName: keyVault.outputs.name
connectionStringKey: 'AZURE-SQL-CATALOG-CONNECTION-STRING'
}
}
// The application database: Identity
module identityDb './core/database/sqlserver/sqlserver.bicep' = {
name: 'sql-identity'
scope: rg
params: {
name: !empty(identityDatabaseServerName) ? identityDatabaseServerName : '${abbrs.sqlServers}identity-${resourceToken}'
databaseName: identityDatabaseName
location: location
tags: tags
sqlAdminPassword: sqlAdminPassword
appUserPassword: appUserPassword
keyVaultName: keyVault.outputs.name
connectionStringKey: 'AZURE-SQL-IDENTITY-CONNECTION-STRING'
}
}
// Store secrets in a keyvault
module keyVault './core/security/keyvault.bicep' = {
name: 'keyvault'
scope: rg
params: {
name: !empty(keyVaultName) ? keyVaultName : '${abbrs.keyVaultVaults}${resourceToken}'
location: location
tags: tags
principalId: principalId
}
}
// Create an App Service Plan to group applications under the same payment plan and SKU
module appServicePlan './core/host/appserviceplan.bicep' = {
name: 'appserviceplan'
scope: rg
params: {
name: !empty(appServicePlanName) ? appServicePlanName : '${abbrs.webServerFarms}${resourceToken}'
location: location
tags: tags
sku: {
name: 'B1'
}
}
}
// Data outputs
output AZURE_SQL_CATALOG_CONNECTION_STRING_KEY string = catalogDb.outputs.connectionStringKey
output AZURE_SQL_IDENTITY_CONNECTION_STRING_KEY string = identityDb.outputs.connectionStringKey
output AZURE_SQL_CATALOG_DATABASE_NAME string = catalogDb.outputs.databaseName
output AZURE_SQL_IDENTITY_DATABASE_NAME string = identityDb.outputs.databaseName
// App outputs
output AZURE_LOCATION string = location
output AZURE_TENANT_ID string = tenant().tenantId
output AZURE_KEY_VAULT_ENDPOINT string = keyVault.outputs.endpoint
output AZURE_KEY_VAULT_NAME string = keyVault.outputs.name

View File

@@ -0,0 +1,21 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"environmentName": {
"value": "${AZURE_ENV_NAME}"
},
"location": {
"value": "${AZURE_LOCATION}"
},
"principalId": {
"value": "${AZURE_PRINCIPAL_ID}"
},
"sqlAdminPassword": {
"value": "$(secretOrRandomPassword ${AZURE_KEY_VAULT_NAME} sqlAdminPassword)"
},
"appUserPassword": {
"value": "$(secretOrRandomPassword ${AZURE_KEY_VAULT_NAME} appUserPassword)"
}
}
}

View File

@@ -0,0 +1,13 @@
using Ardalis.Specification;
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate;
namespace Microsoft.eShopWeb.ApplicationCore.Specifications;
public class CustomerOrdersSpecification : Specification<Order>
{
public CustomerOrdersSpecification(string buyerId)
{
Query.Where(o => o.BuyerId == buyerId)
.Include(o => o.OrderItems);
}
}

View File

@@ -1,7 +1,7 @@
{
"ConnectionStrings": {
"CatalogConnection": "Server=sqlserver,1433;Integrated Security=true;Initial Catalog=Microsoft.eShopOnWeb.CatalogDb;User Id=sa;Password=@someThingComplicated1234;Trusted_Connection=false;",
"IdentityConnection": "Server=sqlserver,1433;Integrated Security=true;Initial Catalog=Microsoft.eShopOnWeb.Identity;User Id=sa;Password=@someThingComplicated1234;Trusted_Connection=false;"
"CatalogConnection": "Server=sqlserver,1433;Integrated Security=true;Initial Catalog=Microsoft.eShopOnWeb.CatalogDb;User Id=sa;Password=@someThingComplicated1234;Trusted_Connection=false;TrustServerCertificate=true;",
"IdentityConnection": "Server=sqlserver,1433;Integrated Security=true;Initial Catalog=Microsoft.eShopOnWeb.Identity;User Id=sa;Password=@someThingComplicated1234;Trusted_Connection=false;TrustServerCertificate=true;"
},
"baseUrls": {
"apiBase": "http://localhost:5200/api/",

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using MediatR;
using MediatR;
using Microsoft.eShopWeb.Web.ViewModels;
namespace Microsoft.eShopWeb.Web.Features.MyOrders;

View File

@@ -18,20 +18,12 @@ public class GetMyOrdersHandler : IRequestHandler<GetMyOrders, IEnumerable<Order
public async Task<IEnumerable<OrderViewModel>> Handle(GetMyOrders request,
CancellationToken cancellationToken)
{
var specification = new CustomerOrdersWithItemsSpecification(request.UserName);
var specification = new CustomerOrdersSpecification(request.UserName);
var orders = await _orderRepository.ListAsync(specification, cancellationToken);
return orders.Select(o => new OrderViewModel
{
OrderDate = o.OrderDate,
OrderItems = o.OrderItems.Select(oi => new OrderItemViewModel()
{
PictureUrl = oi.ItemOrdered.PictureUri,
ProductId = oi.ItemOrdered.CatalogItemId,
ProductName = oi.ItemOrdered.ProductName,
UnitPrice = oi.UnitPrice,
Units = oi.Units
}).ToList(),
OrderNumber = o.Id,
ShippingAddress = o.ShipToAddress,
Total = o.Total()

View File

@@ -3,7 +3,7 @@ using Microsoft.eShopWeb.Web.ViewModels;
namespace Microsoft.eShopWeb.Web.Features.OrderDetails;
public class GetOrderDetails : IRequest<OrderViewModel>
public class GetOrderDetails : IRequest<OrderDetailViewModel>
{
public string UserName { get; set; }
public int OrderId { get; set; }

View File

@@ -6,7 +6,7 @@ using Microsoft.eShopWeb.Web.ViewModels;
namespace Microsoft.eShopWeb.Web.Features.OrderDetails;
public class GetOrderDetailsHandler : IRequestHandler<GetOrderDetails, OrderViewModel?>
public class GetOrderDetailsHandler : IRequestHandler<GetOrderDetails, OrderDetailViewModel?>
{
private readonly IReadRepository<Order> _orderRepository;
@@ -15,7 +15,7 @@ public class GetOrderDetailsHandler : IRequestHandler<GetOrderDetails, OrderView
_orderRepository = orderRepository;
}
public async Task<OrderViewModel?> Handle(GetOrderDetails request,
public async Task<OrderDetailViewModel?> Handle(GetOrderDetails request,
CancellationToken cancellationToken)
{
var spec = new OrderWithItemsByIdSpec(request.OrderId);
@@ -26,7 +26,7 @@ public class GetOrderDetailsHandler : IRequestHandler<GetOrderDetails, OrderView
return null;
}
return new OrderViewModel
return new OrderDetailViewModel
{
OrderDate = order.OrderDate,
OrderItems = order.OrderItems.Select(oi => new OrderItemViewModel

View File

@@ -1,5 +1,6 @@
using System.Net.Mime;
using Ardalis.ListStartupServices;
using Azure.Identity;
using BlazorAdmin;
using BlazorAdmin.Services;
using Blazored.LocalStorage;
@@ -8,6 +9,7 @@ using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.EntityFrameworkCore;
using Microsoft.eShopWeb;
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
using Microsoft.eShopWeb.Infrastructure.Data;
@@ -18,10 +20,27 @@ using Microsoft.eShopWeb.Web.HealthChecks;
using Microsoft.Extensions.Diagnostics.HealthChecks;
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddConsole();
Microsoft.eShopWeb.Infrastructure.Dependencies.ConfigureServices(builder.Configuration, builder.Services);
if (builder.Environment.IsDevelopment() || builder.Environment.EnvironmentName == "Docker"){
// Configure SQL Server (local)
Microsoft.eShopWeb.Infrastructure.Dependencies.ConfigureServices(builder.Configuration, builder.Services);
}
else{
// Configure SQL Server (prod)
var credential = new ChainedTokenCredential(new AzureDeveloperCliCredential(), new DefaultAzureCredential());
builder.Configuration.AddAzureKeyVault(new Uri(builder.Configuration["AZURE_KEY_VAULT_ENDPOINT"] ?? ""), credential);
builder.Services.AddDbContext<CatalogContext>(c =>
{
var connectionString = builder.Configuration[builder.Configuration["AZURE_SQL_CATALOG_CONNECTION_STRING_KEY"] ?? ""];
c.UseSqlServer(connectionString, sqlOptions => sqlOptions.EnableRetryOnFailure());
});
builder.Services.AddDbContext<AppIdentityDbContext>(options =>
{
var connectionString = builder.Configuration[builder.Configuration["AZURE_SQL_IDENTITY_CONNECTION_STRING_KEY"] ?? ""];
options.UseSqlServer(connectionString, sqlOptions => sqlOptions.EnableRetryOnFailure());
});
}
builder.Services.AddCookieSettings();

View File

@@ -0,0 +1,6 @@
namespace Microsoft.eShopWeb.Web.ViewModels;
public class OrderDetailViewModel : OrderViewModel
{
public List<OrderItemViewModel> OrderItems { get; set; } = new();
}

View File

@@ -11,5 +11,4 @@ public class OrderViewModel
public decimal Total { get; set; }
public string Status => DEFAULT_STATUS;
public Address? ShippingAddress { get; set; }
public List<OrderItemViewModel> OrderItems { get; set; } = new();
}

View File

@@ -1,4 +1,4 @@
@model OrderViewModel
@model OrderDetailViewModel
@{
ViewData["Title"] = "My Order History";
}

View File

@@ -16,6 +16,8 @@
<PackageReference Include="Ardalis.ListStartupServices" />
<PackageReference Include="Ardalis.Specification" />
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" />
<PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" />
<PackageReference Include="Azure.Identity" />
<PackageReference Include="MediatR" />
<PackageReference Include="BuildBundlerMinifier" Condition="'$(Configuration)'=='Release'" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" />

View File

@@ -17,4 +17,4 @@
},
"AllowedHosts": "*"
}
}
}

View File

@@ -19,7 +19,7 @@
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" />
<DotNetCliToolReference Include="dotnet-xunit" />
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
</ItemGroup>
<ItemGroup>

View File

@@ -9,7 +9,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Moq" />
<PackageReference Include="xunit" />