Skip to content

Commit 93f0b76

Browse files
Merge pull request #63 from Azure-Samples/brecon/ga
Merge eShop/main 5/24
2 parents acdb055 + f395520 commit 93f0b76

File tree

252 files changed

+6343
-4131
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

252 files changed

+6343
-4131
lines changed

.github/dependabot.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ updates:
99
registries:
1010
- public-nuget
1111
schedule:
12-
interval: daily
12+
interval: weekly
1313
open-pull-requests-limit: 15
1414
groups:
1515
Aspire:

Directory.Packages.props

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
44
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
55
<AspnetVersion>8.0.5</AspnetVersion>
6-
<MicrosoftExtensionsVersion>8.4.0</MicrosoftExtensionsVersion>
7-
<EfVersion>8.0.4</EfVersion>
8-
<AspireVersion>8.0.0-preview.7.24251.11</AspireVersion>
6+
<MicrosoftExtensionsVersion>8.5.0</MicrosoftExtensionsVersion>
7+
<EfVersion>8.0.5</EfVersion>
8+
<AspireVersion>8.0.0</AspireVersion>
9+
<AspireUnstablePackagesVersion>8.0.0-preview.8.24258.2</AspireUnstablePackagesVersion>
910
<GrpcVersion>2.62.0</GrpcVersion>
1011
<DuendeVersion>7.0.4</DuendeVersion>
12+
<ApiVersioningVersion>8.1.0</ApiVersioningVersion>
1113
</PropertyGroup>
1214
<ItemGroup>
1315
<!-- Version together with Aspire -->
@@ -23,10 +25,13 @@
2325
<PackageVersion Include="Aspire.Npgsql" Version="$(AspireVersion)" />
2426
<PackageVersion Include="Aspire.Npgsql.EntityFrameworkCore.PostgreSQL" Version="$(AspireVersion)" />
2527
<PackageVersion Include="Aspire.StackExchange.Redis" Version="$(AspireVersion)" />
26-
<PackageVersion Include="Aspire.Azure.AI.OpenAI" Version="$(AspireVersion)" />
28+
<PackageVersion Include="Aspire.Azure.AI.OpenAI" Version="$(AspireUnstablePackagesVersion)" />
2729
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery" Version="$(AspireVersion)" />
2830
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery.Yarp" Version="$(AspireVersion)" />
2931
<!-- Version together with ASP.NET -->
32+
<PackageVersion Include="Asp.Versioning.Http" Version="$(ApiVersioningVersion)" />
33+
<PackageVersion Include="Asp.Versioning.Http.Client" Version="$(ApiVersioningVersion)" />
34+
<PackageVersion Include="Asp.Versioning.Mvc.ApiExplorer" Version="$(ApiVersioningVersion)" />
3035
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="$(AspnetVersion)" />
3136
<PackageVersion Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="$(AspnetVersion)" />
3237
<PackageVersion Include="Microsoft.AspNetCore.Components.QuickGrid" Version="$(AspnetVersion)" />
@@ -39,7 +44,7 @@
3944
<PackageVersion Include="Microsoft.Extensions.Identity.Stores" Version="$(AspnetVersion)" />
4045
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="$(MicrosoftExtensionsVersion)" />
4146
<!-- Version together with EF -->
42-
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.2" />
47+
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.4" />
4348
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="$(EfVersion)" />
4449
<PackageVersion Include="NSubstitute" Version="5.1.0" />
4550
<PackageVersion Include="NSubstitute.Analyzers.CSharp" Version="1.0.17" />
@@ -53,6 +58,7 @@
5358
<PackageVersion Include="AspNetCore.HealthChecks.Uris" Version="8.0.1" />
5459
<!-- AI -->
5560
<PackageVersion Include="Microsoft.SemanticKernel" Version="1.13.0" />
61+
<PackageVersion Include="Microsoft.SemanticKernel.Connectors.Onnx" Version="1.10.0-alpha" />
5662
<!-- Open Telemetry -->
5763
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.8.1" />
5864
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.8.1" />
@@ -78,11 +84,11 @@
7884
<PackageVersion Include="FluentValidation.AspNetCore" Version="11.3.0" />
7985
<PackageVersion Include="MediatR" Version="12.2.0" />
8086
<PackageVersion Include="Microsoft.Web.LibraryManager.Build" Version="2.1.175" />
81-
<PackageVersion Include="Polly" Version="8.3.1" />
82-
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.5.0" />
87+
<PackageVersion Include="Polly.Core" Version="8.4.0" />
88+
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.6.1" />
8389
<PackageVersion Include="System.Reflection.TypeExtensions" Version="4.7.0" />
8490
<PackageVersion Include="xunit" Version="2.8.0" />
8591
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.0" />
8692
<PackageVersion Include="Yarp.ReverseProxy" Version="2.1.0" />
8793
</ItemGroup>
88-
</Project>
94+
</Project>

README.md

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# eShop Reference Application - "Northern Mountains"
1+
# eShop Reference Application - "AdventureWorks"
22

3-
A reference .NET application implementing an eCommerce web site using a services-based architecture.
3+
A reference .NET application implementing an e-commerce website using a services-based architecture.
44

55
![eShop Reference Application architecture diagram](img/eshop_architecture.png)
66

@@ -11,18 +11,30 @@ A reference .NET application implementing an eCommerce web site using a services
1111
### Prerequisites
1212

1313
- Clone the eShop repository: https://github.com/Azure-Samples/eshopOnAzure
14-
- (Windows only) Install Visual Studio. Visual Studio contains tooling support for .NET Aspire that you will want to have. [Visual Studio 2022 version 17.10 Preview](https://visualstudio.microsoft.com/vs/preview/).
15-
- During installation, ensure that the following are selected:
14+
- Install & start Docker Desktop: https://docs.docker.com/engine/install/
15+
16+
#### Windows with Visual Studio
17+
- Install [Visual Studio 2022 version 17.10 or newer](https://visualstudio.microsoft.com/vs/).
18+
- Select the following workloads:
1619
- `ASP.NET and web development` workload.
1720
- `.NET Aspire SDK` component in `Individual components`.
18-
- Install the latest [.NET 8 SDK](https://github.com/dotnet/installer#installers-and-binaries)
19-
- On Mac/Linux (or if not using Visual Studio), install the Aspire workload with the following commands:
21+
- Optional: `.NET Multi-platform App UI development` to run client apps
22+
23+
#### Mac, Linux, & Windows without Visual Studio
24+
- Install the latest [.NET 8 SDK](https://dot.net/download?cid=eshop)
25+
- Install the [.NET Aspire workload](https://learn.microsoft.com/dotnet/aspire/fundamentals/setup-tooling?tabs=dotnet-cli%2Cunix#install-net-aspire) with the following commands:
2026
```powershell
2127
dotnet workload update
2228
dotnet workload install aspire
2329
dotnet restore eShop.Web.slnf
2430
```
25-
- Install & start Docker Desktop: https://docs.docker.com/engine/install/
31+
32+
> Note: These commands may require `sudo`
33+
34+
- Optional: Install [Visual Studio Code with C# Dev Kit](https://code.visualstudio.com/docs/csharp/get-started)
35+
- Optional: Install [.NET MAUI Workload](https://learn.microsoft.com/dotnet/maui/get-started/installation?tabs=visual-studio-code)
36+
37+
> Note: When running on Mac with Apple Silicon (M series processor), Rosetta 2 for grpc-tools.
2638
2739
### Running the solution
2840

@@ -40,18 +52,34 @@ dotnet run --project src/eShop.AppHost/eShop.AppHost.csproj
4052
```
4153
then look for lines like this in the console output in order to find the URL to open the Aspire dashboard:
4254
```sh
43-
Now listening on: http://localhost:18848
55+
Login to the dashboard at: http://localhost:19888/login?t=uniquelogincodeforyou
4456
```
4557

46-
### Sample data
58+
> You may need to install ASP.NET Core HTTPS development certificates first, and then close all browser tabs. Learn more at https://aka.ms/aspnet/https-trust-dev-cert
4759
48-
The sample catalog data is defined in [catalog.json](https://github.com/dotnet/eShop/blob/main/src/Catalog.API/Setup/catalog.json). Those product names, descriptions, and brand names are fictional and were generated using [GPT-35-Turbo](https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/chatgpt), and the corresponding [product images](https://github.com/dotnet/eShop/tree/main/src/Catalog.API/Pics) were generated using [DALL·E 3](https://openai.com/dall-e-3).
60+
### Azure Open AI
61+
62+
When using Azure OpenAI, inside *eShop.AppHost/appsettings.json*, add the following section:
63+
64+
```json
65+
"ConnectionStrings": {
66+
"OpenAi": "Endpoint=xxx;Key=xxx;"
67+
}
68+
```
69+
70+
Replace the values with your own. Then, in the eShop.AppHost *Program.cs*, set this value to **true**
71+
72+
```csharp
73+
bool useOpenAI = false;
74+
```
75+
76+
Here's additional guidance on the [.NET Aspire OpenAI component](https://learn.microsoft.com/dotnet/aspire/azureai/azureai-openai-component?tabs=dotnet-cli).
4977

50-
## Use Azure Developer CLI
78+
### Use Azure Developer CLI
5179

5280
You can use the [Azure Developer CLI](https://aka.ms/azd) to run this project on Azure with only a few commands. Follow the next instructions:
5381

54-
- Install [azd](https://aka.ms/azure-dev/install).
82+
- Install the latest or update to the latest [Azure Developer CLI (azd)](https://aka.ms/azure-dev/install).
5583
- Log in `azd` (if you haven't done it before) to your Azure account:
5684
```sh
5785
azd auth login
@@ -61,8 +89,8 @@ azd auth login
6189
azd init
6290
```
6391
- During init:
64-
- Select `Use code in the current directory`. Azd will automatically detect the Dotnet Aspire project.
65-
- Confirm `.Net (Aspire)` and continue.
92+
- Select `Use code in the current directory`. Azd will automatically detect the .NET Aspire project.
93+
- Confirm `.NET (Aspire)` and continue.
6694
- Select which services to expose to the Internet (exposing `webapp` is enough to test the sample).
6795
- Finalize the initialization by giving a name to your environment.
6896

@@ -79,7 +107,11 @@ Notes:
79107

80108
## Contributing
81109

82-
For more information on contributing to this repo, please read [the contribution documentation](./CONTRIBUTING.md) and [the Code of Conduct](CODE-OF-CONDUCT.md).
110+
For more information on contributing to this repo, read [the contribution documentation](./CONTRIBUTING.md) and [the Code of Conduct](CODE-OF-CONDUCT.md).
111+
112+
### Sample data
113+
114+
The sample catalog data is defined in [catalog.json](https://github.com/dotnet/eShop/blob/main/src/Catalog.API/Setup/catalog.json). Those product names, descriptions, and brand names are fictional and were generated using [GPT-35-Turbo](https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/chatgpt), and the corresponding [product images](https://github.com/dotnet/eShop/tree/main/src/Catalog.API/Pics) were generated using [DALL·E 3](https://openai.com/dall-e-3).
83115

84116
### Other eShops
85117

src/Catalog.API/AIOptions.cs

Lines changed: 0 additions & 14 deletions
This file was deleted.

src/Catalog.API/Apis/CatalogApi.cs

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,30 @@ namespace eShop.Catalog.API;
55

66
public static class CatalogApi
77
{
8-
public static IEndpointRouteBuilder MapCatalogApi(this IEndpointRouteBuilder app)
8+
public static IEndpointRouteBuilder MapCatalogApiV1(this IEndpointRouteBuilder app)
99
{
10+
var api = app.MapGroup("api/catalog").HasApiVersion(1.0);
11+
1012
// Routes for querying catalog items.
11-
app.MapGet("/items", GetAllItems);
12-
app.MapGet("/items/by", GetItemsByIds);
13-
app.MapGet("/items/{id:int}", GetItemById);
14-
app.MapGet("/items/by/{name:minlength(1)}", GetItemsByName);
15-
app.MapGet("/items/{catalogItemId:int}/pic", GetItemPictureById);
13+
api.MapGet("/items", GetAllItems);
14+
api.MapGet("/items/by", GetItemsByIds);
15+
api.MapGet("/items/{id:int}", GetItemById);
16+
api.MapGet("/items/by/{name:minlength(1)}", GetItemsByName);
17+
api.MapGet("/items/{catalogItemId:int}/pic", GetItemPictureById);
1618

1719
// Routes for resolving catalog items using AI.
18-
app.MapGet("/items/withsemanticrelevance/{text:minlength(1)}", GetItemsBySemanticRelevance);
20+
api.MapGet("/items/withsemanticrelevance/{text:minlength(1)}", GetItemsBySemanticRelevance);
1921

2022
// Routes for resolving catalog items by type and brand.
21-
app.MapGet("/items/type/{typeId}/brand/{brandId?}", GetItemsByBrandAndTypeId);
22-
app.MapGet("/items/type/all/brand/{brandId:int?}", GetItemsByBrandId);
23-
app.MapGet("/catalogtypes", async (CatalogContext context) => await context.CatalogTypes.OrderBy(x => x.Type).ToListAsync());
24-
app.MapGet("/catalogbrands", async (CatalogContext context) => await context.CatalogBrands.OrderBy(x => x.Brand).ToListAsync());
23+
api.MapGet("/items/type/{typeId}/brand/{brandId?}", GetItemsByBrandAndTypeId);
24+
api.MapGet("/items/type/all/brand/{brandId:int?}", GetItemsByBrandId);
25+
api.MapGet("/catalogtypes", async (CatalogContext context) => await context.CatalogTypes.OrderBy(x => x.Type).ToListAsync());
26+
api.MapGet("/catalogbrands", async (CatalogContext context) => await context.CatalogBrands.OrderBy(x => x.Brand).ToListAsync());
2527

2628
// Routes for modifying catalog items.
27-
app.MapPut("/items", UpdateItem);
28-
app.MapPost("/items", CreateItem);
29-
app.MapDelete("/items/{id:int}", DeleteItemById);
29+
api.MapPut("/items", UpdateItem);
30+
api.MapPost("/items", CreateItem);
31+
api.MapDelete("/items/{id:int}", DeleteItemById);
3032

3133
return app;
3234
}
@@ -126,7 +128,7 @@ public static async Task<Results<BadRequest<string>, RedirectToRouteHttpResult,
126128

127129
if (!services.CatalogAI.IsEnabled)
128130
{
129-
return await GetItemsByName(paginationRequest, services, text);
131+
return await GetItemsByName(paginationRequest, services, text);
130132
}
131133

132134
// Create an embedding for the input search
@@ -250,7 +252,7 @@ public static async Task<Results<Created, NotFound<string>>> UpdateItem(
250252
{
251253
await services.Context.SaveChangesAsync();
252254
}
253-
return TypedResults.Created($"/api/v1/catalog/items/{productToUpdate.Id}");
255+
return TypedResults.Created($"/api/catalog/items/{productToUpdate.Id}");
254256
}
255257

256258
public static async Task<Created> CreateItem(
@@ -275,7 +277,7 @@ public static async Task<Created> CreateItem(
275277
services.Context.CatalogItems.Add(item);
276278
await services.Context.SaveChangesAsync();
277279

278-
return TypedResults.Created($"/api/v1/catalog/items/{item.Id}");
280+
return TypedResults.Created($"/api/catalog/items/{item.Id}");
279281
}
280282

281283
public static async Task<Results<NoContent, NotFound>> DeleteItemById(

src/Catalog.API/Catalog.API.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<PropertyGroup>
44
<TargetFramework>net8.0</TargetFramework>
55
<UserSecretsId>d1b521ec-3411-4d39-98c6-8509466ed471</UserSecretsId>
6+
<NoWarn>$(NoWarn);SKEXP0001;SKEXP0010;SKEXP0070</NoWarn>
67
</PropertyGroup>
78

89
<ItemGroup>
@@ -15,6 +16,7 @@
1516
</ItemGroup>
1617

1718
<ItemGroup>
19+
<PackageReference Include="Asp.Versioning.Http" />
1820
<PackageReference Include="Aspire.Npgsql.EntityFrameworkCore.PostgreSQL" />
1921
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools">
2022
<PrivateAssets>all</PrivateAssets>
@@ -25,6 +27,8 @@
2527
<!-- AI -->
2628
<ItemGroup>
2729
<PackageReference Include="Aspire.Azure.AI.OpenAI" />
30+
<PackageReference Include="Microsoft.SemanticKernel" />
31+
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Onnx" />
2832
<PackageReference Include="Pgvector" />
2933
<PackageReference Include="Pgvector.EntityFrameworkCore" />
3034
</ItemGroup>

src/Catalog.API/Catalog.API.http

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
@Catalog.API_HostAddress = http://localhost:5222
2+
@ApiVersion = 1.0
23

3-
4-
GET {{Catalog.API_HostAddress}}/api/v1/catalog/items
4+
GET {{Catalog.API_HostAddress}}/api/catalog/items?api-version={{ApiVersion}}
55

66
###
77

8-
GET {{Catalog.API_HostAddress}}/api/v1/catalog/items/type/1/brand/2
8+
GET {{Catalog.API_HostAddress}}/api/catalog/items/type/1/brand/2?api-version={{ApiVersion}}
99

1010
###

src/Catalog.API/Extensions/Extensions.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using eShop.Catalog.API.Services;
22
using eShop.EventBusServiceBus;
3+
using Microsoft.SemanticKernel;
34

45
public static class Extensions
56
{
@@ -28,12 +29,15 @@ public static void AddApplicationServices(this IHostApplicationBuilder builder)
2829
builder.Services.AddOptions<CatalogOptions>()
2930
.BindConfiguration(nameof(CatalogOptions));
3031

31-
builder.Services.AddOptions<AIOptions>()
32-
.BindConfiguration("AI");
33-
34-
if (!string.IsNullOrWhiteSpace(builder.Configuration.GetConnectionString("openai")))
32+
if (builder.Configuration["AI:Onnx:EmbeddingModelPath"] is string modelPath &&
33+
builder.Configuration["AI:Onnx:EmbeddingVocabPath"] is string vocabPath)
34+
{
35+
builder.Services.AddBertOnnxTextEmbeddingGeneration(modelPath, vocabPath);
36+
}
37+
else if (!string.IsNullOrWhiteSpace(builder.Configuration.GetConnectionString("openai")))
3538
{
3639
builder.AddAzureOpenAIClient("openai");
40+
builder.Services.AddOpenAITextEmbeddingGeneration(builder.Configuration["AIOptions:OpenAI:EmbeddingName"] ?? "text-embedding-3-small");
3741
}
3842

3943
builder.Services.AddSingleton<ICatalogAI, CatalogAI>();

src/Catalog.API/GlobalUsings.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
global using eShop.Catalog.API;
1+
global using Asp.Versioning;
2+
global using Asp.Versioning.Conventions;
3+
global using eShop.Catalog.API;
24
global using eShop.Catalog.API.Infrastructure;
35
global using eShop.Catalog.API.Infrastructure.EntityConfigurations;
46
global using eShop.Catalog.API.Infrastructure.Exceptions;

0 commit comments

Comments
 (0)