### Install and Configure Development Environment (VS Code) Source: https://github.com/dotnet/eshop/blob/main/README.md These PowerShell commands automate the setup of Visual Studio Code and related extensions for development on Mac, Linux, and Windows without Visual Studio. A restart is required. ```powershell install_module -Name Microsoft.WinGet.Configuration -AllowPrerelease -AcceptLicense -Force $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") get-WinGetConfiguration -file .\.configurations\vscode.dsc.yaml | Invoke-WinGetConfiguration -AcceptConfigurationAgreements ``` -------------------------------- ### Basket API gRPC Client Example (C#) Source: https://context7.com/dotnet/eshop/llms.txt Provides a C# example for interacting with the Basket gRPC service. Demonstrates authenticated and anonymous calls. ```csharp // C# gRPC client example using var channel = GrpcChannel.ForAddress("https://localhost:5103"); var client = new Basket.BasketClient(channel); // GetBasket — anonymous call allowed var basket = await client.GetBasketAsync(new GetBasketRequest(), headers: new Metadata { { "Authorization", $"Bearer {accessToken}" } }); Console.WriteLine($"Items in basket: {basket.Items.Count}"); // Items in basket: 2 // UpdateBasket — requires authentication var response = await client.UpdateBasketAsync(new UpdateBasketRequest { Items = { new BasketItem { ProductId = 7, Quantity = 2 }, new BasketItem { ProductId = 14, Quantity = 1 } } }, headers: new Metadata { { "Authorization", $"Bearer {accessToken}" } }); // DeleteBasket await client.DeleteBasketAsync(new DeleteBasketRequest(), headers: new Metadata { { "Authorization", $"Bearer {accessToken}" } }); // RpcException(StatusCode.Unauthenticated) thrown if no Bearer token on UpdateBasket/DeleteBasket ``` -------------------------------- ### Configure IdentityServer OAuth 2.0 / OIDC Client Source: https://context7.com/dotnet/eshop/llms.txt Set up Identity API client configurations, including scopes and authentication flows. This example shows MAUI client setup for Authorization Code + PKCE flow. ```csharp // Configured scopes and clients (Config.cs) // API scopes: "orders", "basket", "webhooks" // webapp client — Authorization Code, no PKCE, offline_access // maui client — Authorization Code + PKCE, offline_access, AllowAccessTokensViaBrowser // Registering identity validation in a downstream service (e.g., Basket.API) // appsettings.json: { "Identity": { "Audience": "basket", "Url": "https://identity-api" // set by Aspire via WithEnvironment } } // Acquiring a token from Identity API (MAUI client example) var oidcClient = new OidcClient(new OidcClientOptions { Authority = "https://identity-api", ClientId = "maui", ClientSecret = "secret", Scope = "openid profile offline_access orders basket webhooks", RedirectUri = "eshop://callback", Flow = OidcClientOptions.AuthenticationFlow.AuthorizationCode }); var loginResult = await oidcClient.LoginAsync(new LoginRequest()); string accessToken = loginResult.AccessToken; // Use token in HTTP requests httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); ``` -------------------------------- ### Run eShop Reference Application with .NET Aspire Source: https://context7.com/dotnet/eshop/llms.txt Use this command to start all services of the eShop reference application. Ensure Docker Desktop is running. The Aspire dashboard URL will be printed in the console. ```bash # Requires Docker Desktop running dotnet run --project src/eShop.AppHost/eShop.AppHost.csproj # Then open the Aspire dashboard URL printed in the console, e.g.: # Login to the dashboard at: http://localhost:19888/login?t= ``` -------------------------------- ### Install and Configure Development Environment (Windows) Source: https://github.com/dotnet/eshop/blob/main/README.md Use these PowerShell commands to automatically configure your Windows environment with the necessary tools to build and run the eShop application. A restart is required after execution. ```powershell install_module -Name Microsoft.WinGet.Configuration -AllowPrerelease -AcceptLicense -Force $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") get-WinGetConfiguration -file .\.configurations\vside.dsc.yaml | Invoke-WinGetConfiguration -AcceptConfigurationAgreements ``` -------------------------------- ### GET /api/webhooks Source: https://context7.com/dotnet/eshop/llms.txt Lists all webhook subscriptions for the authenticated user. ```APIDOC ## GET /api/webhooks — List my webhook subscriptions ### Description Lists all webhook subscriptions for the authenticated user. ### Method GET ### Endpoint /api/webhooks ### Parameters #### Headers - **Authorization** (string) - Required - Bearer token for authentication. ### Response #### Success Response (200 OK) - Returns a list of webhook subscriptions, each with an ID, type, destination URL, and date. #### Response Example ```json [ { "id": 3, "type": "CatalogItemPriceChange", "destUrl": "https://myapp.example.com/hooks/eshop", "date": "2024-11-01T12:00:00Z" } ] ``` ``` -------------------------------- ### Get Catalog Item Picture Source: https://context7.com/dotnet/eshop/llms.txt Streams the image file for a catalog item. Responds with the appropriate MIME type. ```bash curl -o item7.webp "http://localhost:5222/api/catalog/items/7/pic?api-version=1.0" # 200 OK → binary image stream (Content-Type: image/webp) # 404 Not Found → item or picture does not exist ``` -------------------------------- ### GET /api/orders Source: https://context7.com/dotnet/eshop/llms.txt Returns a summary list of all orders belonging to the authenticated user. ```APIDOC ## GET /api/orders — List orders for current user ### Description Returns a summary list of all orders belonging to the authenticated user. ### Method GET ### Endpoint /api/orders ### Parameters #### Headers - **Authorization** (string) - Required - Bearer token for authentication. ### Response #### Success Response (200 OK) - Returns a list of order summaries, each including order number, date, status, and total. #### Response Example ```json [ { "orderNumber": 5, "date": "2024-11-01T14:22:00Z", "status": "Shipped", "total": 32.50 }, { "orderNumber": 3, "date": "2024-10-15T09:00:00Z", "status": "Cancelled", "total": 18.00 } ] ``` ``` -------------------------------- ### Get Order by ID Source: https://context7.com/dotnet/eshop/llms.txt Retrieves a specific order using its unique identifier. ```bash curl "http://localhost:5224/api/orders/5" \ -H "Authorization: Bearer $TOKEN" ``` -------------------------------- ### GET /api/orders/cardtypes Source: https://context7.com/dotnet/eshop/llms.txt Lists the available payment card types. ```APIDOC ## GET /api/orders/cardtypes — List payment card types ### Description Lists the available payment card types. ### Method GET ### Endpoint /api/orders/cardtypes ### Parameters #### Headers - **Authorization** (string) - Required - Bearer token for authentication. ### Response #### Success Response (200 OK) - Returns a list of card types, each with an ID and name. #### Response Example ```json [{"id":1,"name":"Amex"},{"id":2,"name":"Visa"},{"id":3,"name":"MasterCard"}] ``` ``` -------------------------------- ### Get Webhook Subscription by ID Source: https://context7.com/dotnet/eshop/llms.txt Retrieves a specific webhook subscription using its unique identifier. ```bash curl "http://localhost:5228/api/webhooks/3" \ -H "Authorization: Bearer $TOKEN" ``` -------------------------------- ### Get item picture Source: https://context7.com/dotnet/eshop/llms.txt Streams the image file for a catalog item; responds with the appropriate MIME type (`image/webp`, `image/png`, etc.). ```APIDOC ## GET /api/catalog/items/{id}/pic — Get item picture ### Description Streams the image file for a catalog item; responds with the appropriate MIME type (`image/webp`, `image/png`, etc.). ### Method GET ### Endpoint /api/catalog/items/{id}/pic ### Parameters #### Path Parameters - **id** (integer) - Required - The ID of the catalog item. #### Query Parameters - **api-version** (string) - Required - The API version, e.g., "1.0". ### Response #### Success Response (200 OK) - Binary image stream (Content-Type: image/webp, image/png, etc.) #### Error Response - 404 Not Found — item or picture does not exist ``` -------------------------------- ### GET /api/orders/{orderId} Source: https://context7.com/dotnet/eshop/llms.txt Retrieves a specific order by its ID. ```APIDOC ## GET /api/orders/{orderId} — Get order by ID ### Description Retrieves a specific order by its ID. ### Method GET ### Endpoint /api/orders/{orderId} ### Parameters #### Path Parameters - **orderId** (integer) - Required - The ID of the order to retrieve. #### Headers - **Authorization** (string) - Required - Bearer token for authentication. ### Response #### Success Response (200 OK) - Returns an order object with details such as order number, date, status, shipping address, total, and order items. #### Response Example ```json { "orderNumber": 5, "date": "2024-11-01T14:22:00Z", "status": "Submitted", "city": "Seattle", "country": "US", "total": 32.50, "orderItems": [ { "productName": "Roslyn Shirt", "units": 2, "unitPrice": 12.00 } ] } ``` #### Error Response (404 Not Found) - "order does not exist" ``` -------------------------------- ### Batch Get Catalog Items by IDs with cURL Source: https://context7.com/dotnet/eshop/llms.txt Efficiently retrieve multiple catalog items in a single request by providing an array of IDs. Uses API version 1.0. ```bash curl "http://localhost:5222/api/catalog/items/by?ids=1&ids=3&ids=7&api-version=1.0" # 200 OK → JSON array of matching CatalogItem objects ``` -------------------------------- ### Remove Webhook Subscription using cURL Source: https://context7.com/dotnet/eshop/llms.txt Demonstrates how to remove a webhook subscription using the DELETE HTTP method. Includes example responses for successful removal and when the subscription is not found. ```bash curl -X DELETE "http://localhost:5228/api/webhooks/3" \ -H "Authorization: Bearer $TOKEN" # 202 Accepted — subscription removed # 404 Not Found — "Subscriptions 3 not found" ``` -------------------------------- ### Batch Get Items by IDs Source: https://context7.com/dotnet/eshop/llms.txt Returns a list of catalog items that match the provided array of IDs in a single API call. ```APIDOC ## GET /api/catalog/items/by — Batch get items by IDs ### Description Returns a list of catalog items matching the provided IDs array in a single round-trip. ### Method GET ### Endpoint /api/catalog/items/by #### Query Parameters - **ids** (array of integers) - Required - An array of item IDs to retrieve. - **api-version** (string) - Required - Specifies the API version (e.g., `1.0`). ### Request Example ```bash curl "http://localhost:5222/api/catalog/items/by?ids=1&ids=3&ids=7&api-version=1.0" ``` ### Response #### Success Response (200) - JSON array of matching CatalogItem objects. ``` -------------------------------- ### GET /api/webhooks/{id} Source: https://context7.com/dotnet/eshop/llms.txt Retrieves a specific webhook subscription by its ID. ```APIDOC ## GET /api/webhooks/{id} — Get webhook subscription by ID ### Description Retrieves a specific webhook subscription by its ID. ### Method GET ### Endpoint /api/webhooks/{id} ### Parameters #### Path Parameters - **id** (integer) - Required - The ID of the webhook subscription to retrieve. #### Headers - **Authorization** (string) - Required - Bearer token for authentication. ### Response #### Success Response (200 OK) - Returns the `WebhookSubscription` object. #### Error Response (404 Not Found) - "Subscriptions {id} not found" ``` -------------------------------- ### Get Single Catalog Item Source: https://context7.com/dotnet/eshop/llms.txt Retrieves a single catalog item by its ID. Returns `404` if the item is not found and `400` for invalid IDs. ```APIDOC ## GET /api/catalog/items/{id} — Get single catalog item ### Description Retrieves a single item including its brand, returns `404` when not found and `400` for invalid ids. ### Method GET ### Endpoint /api/catalog/items/{id} #### Path Parameters - **id** (integer) - Required - The unique identifier of the catalog item. #### Query Parameters - **api-version** (string) - Required - Specifies the API version (e.g., `1.0`). ### Request Example ```bash curl "http://localhost:5222/api/catalog/items/7?api-version=1.0" ``` ### Response #### Success Response (200) - CatalogItem JSON with CatalogBrand populated. #### Error Response (404) - Not Found → empty body #### Error Response (400) - Bad Request → `{ "detail": "Id is not valid" }` ### Example Usage ```bash curl "http://localhost:5222/api/catalog/items/0?api-version=1.0" # 400 Bad Request ``` ``` -------------------------------- ### Get Single Catalog Item with cURL Source: https://context7.com/dotnet/eshop/llms.txt Retrieve a specific catalog item by its ID using API version 1.0. Handles `404 Not Found` for missing items and `400 Bad Request` for invalid IDs. ```bash curl "http://localhost:5222/api/catalog/items/7?api-version=1.0" # 200 OK → CatalogItem JSON with CatalogBrand populated # 404 Not Found → empty body # 400 Bad Request → { "detail": "Id is not valid" } ``` ```bash curl "http://localhost:5222/api/catalog/items/0?api-version=1.0" # 400 Bad Request ``` -------------------------------- ### Create Azure Resources and Deploy Sample Source: https://github.com/dotnet/eshop/blob/main/README.md Creates the necessary Azure resources and deploys the eShop sample application. This command can be run again to update the sample after saving changes. ```sh azd up ``` -------------------------------- ### Load Raw Asset at Runtime Source: https://github.com/dotnet/eshop/blob/main/src/ClientApp/Resources/Raw/AboutAssets.txt Use FileSystem.OpenAppPackageFileAsync to open a stream to the asset. Ensure the file has the 'MauiAsset' build action. This method is part of .NET MAUI Essentials. ```csharp async Task LoadMauiAsset() { using var stream = await FileSystem.OpenAppPackageFileAsync("AboutAssets.txt"); using var reader = new StreamReader(stream); var contents = reader.ReadToEnd(); } ``` -------------------------------- ### Configure eShop AppHost with .NET Aspire Source: https://context7.com/dotnet/eshop/llms.txt This C# code configures the infrastructure for the eShop reference application using .NET Aspire. It sets up Redis, RabbitMQ, and PostgreSQL databases, and defines project references and health checks. ```csharp // src/eShop.AppHost/Program.cs — infrastructure wiring var builder = DistributedApplication.CreateBuilder(args); var redis = builder.AddRedis("redis"); var rabbitMq = builder.AddRabbitMQ("eventbus").WithLifetime(ContainerLifetime.Persistent); var postgres = builder.AddPostgres("postgres") .WithImage("ankane/pgvector").WithImageTag("latest") .WithLifetime(ContainerLifetime.Persistent); var catalogDb = postgres.AddDatabase("catalogdb"); var orderDb = postgres.AddDatabase("orderingdb"); var catalogApi = builder.AddProject("catalog-api") .WithReference(rabbitMq).WaitFor(rabbitMq) .WithReference(catalogDb); var orderingApi = builder.AddProject("ordering-api") .WithReference(rabbitMq).WaitFor(rabbitMq) .WithReference(orderDb).WaitFor(orderDb) .WithHttpHealthCheck("/health"); builder.AddProject("webapp") .WithExternalHttpEndpoints() .WithReference(basketApi) .WithReference(catalogApi) .WithReference(orderingApi) .WaitFor(identityApi); builder.Build().Run(); // Expected: Aspire dashboard URL printed; all containers started automatically ``` -------------------------------- ### Include Raw Assets in .csproj Source: https://github.com/dotnet/eshop/blob/main/src/HybridApp/Resources/Raw/AboutAssets.txt Use the `MauiAsset` build action to include all files in the `Resources\Raw` directory and its subdirectories. The `LogicalName` ensures files are deployed with their original relative paths. ```xml ``` -------------------------------- ### Initialize Azure Developer CLI Source: https://github.com/dotnet/eshop/blob/main/README.md Initializes the Azure Developer CLI in the current directory. It automatically detects the .NET Aspire project and prompts for configuration details. ```sh azd init ``` -------------------------------- ### Publish and Subscribe to Integration Events Source: https://context7.com/dotnet/eshop/llms.txt Demonstrates how to publish integration events using `IEventBus.PublishAsync` and subscribe to them in other services. Publishing is transactional via an outbox pattern. ```APIDOC ## Event Bus — Integration Events ### `IEventBus.PublishAsync` — Publish an integration event All microservices share a `IEventBus` abstraction backed by RabbitMQ. Publishing is transactional in Catalog: the event is saved to an outbox table alongside the EF context changes before dispatch. ```csharp // Publishing a ProductPriceChangedIntegrationEvent (Catalog.API internal) var priceChangedEvent = new ProductPriceChangedIntegrationEvent( ProductId: 7, NewPrice: 129.99m, OldPrice: 149.99m); // Atomic save + publish via outbox pattern await catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(priceChangedEvent); await catalogIntegrationEventService.PublishThroughEventBusAsync(priceChangedEvent); // Subscribing in another service (e.g., Basket.API extensions) builder.AddRabbitMqEventBus("eventbus") .AddSubscription(); // Handler signature public class OrderStatusChangedToAwaitingValidationIntegrationEventHandler : IIntegrationEventHandler { public async Task Handle(OrderStatusChangedToAwaitingValidationIntegrationEvent @event) { // Confirm or reject stock for each order item foreach (var orderStockItem in @event.OrderStockItems) { var catalogItem = await _context.CatalogItems.FindAsync(orderStockItem.ProductId); var hasStock = catalogItem.AvailableStock >= orderStockItem.Units; // publish OrderStockConfirmedIntegrationEvent or OrderStockRejectedIntegrationEvent } } } ``` ``` -------------------------------- ### List Orders for Current User Source: https://context7.com/dotnet/eshop/llms.txt Returns a summary list of all orders belonging to the authenticated user. ```bash curl "http://localhost:5224/api/orders" \ -H "Authorization: Bearer $TOKEN" ``` -------------------------------- ### Configure OpenAPI Documentation in .NET Source: https://context7.com/dotnet/eshop/llms.txt Register and use default OpenAPI documentation and interactive UI in your .NET API services. Ensure 'OpenApi' settings are configured in appsettings.json. ```csharp // Service registration (Program.cs of any API) builder.AddDefaultOpenApi( builder.Services.AddApiVersioning(options => { options.DefaultApiVersion = new ApiVersion(1, 0); options.ReportApiVersions = true; })); // Middleware (Program.cs) app.UseDefaultOpenApi(); // In development, exposes: // GET /openapi/v1.json — OpenAPI v1 spec // GET /openapi/v2.json — OpenAPI v2 spec // GET /scalar/v1 — Scalar interactive UI (default) // GET / — redirects to /scalar/v2 (latest version) ``` ```json // appsettings.json — required to enable OpenAPI { "OpenApi": { "Document": { "Title": "eShop - Catalog HTTP API", "Description": "The Catalog Microservice HTTP API", "Version": "v1" } }, "Identity": { "Scopes": { "catalog": "Catalog API access" } } } ``` -------------------------------- ### Create Order Draft Source: https://context7.com/dotnet/eshop/llms.txt Creates an order draft from basket items to calculate totals before checkout confirmation. ```bash curl -X POST "http://localhost:5224/api/orders/draft" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "buyerId": "abc123", "items": [ { "productId": 7, "productName": "Roslyn Shirt", "unitPrice": 12.00, "units": 2 }, { "productId": 14, "productName": "Prism Mug", "unitPrice": 8.50, "units": 1 } ] }' ``` -------------------------------- ### Publishing and Subscribing to Integration Events with RabbitMQ Source: https://context7.com/dotnet/eshop/llms.txt Shows how to publish integration events using the IEventBus abstraction, which is backed by RabbitMQ. It details the outbox pattern for transactional publishing and how to subscribe to events in other services. ```csharp // Publishing a ProductPriceChangedIntegrationEvent (Catalog.API internal) var priceChangedEvent = new ProductPriceChangedIntegrationEvent( ProductId: 7, NewPrice: 129.99m, OldPrice: 149.99m); // Atomic save + publish via outbox pattern await catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(priceChangedEvent); await catalogIntegrationEventService.PublishThroughEventBusAsync(priceChangedEvent); // Subscribing in another service (e.g., Basket.API extensions) builder.AddRabbitMqEventBus("eventbus") .AddSubscription< OrderStatusChangedToAwaitingValidationIntegrationEvent, OrderStatusChangedToAwaitingValidationIntegrationEventHandler>(); // Handler signature public class OrderStatusChangedToAwaitingValidationIntegrationEventHandler : IIntegrationEventHandler { public async Task Handle(OrderStatusChangedToAwaitingValidationIntegrationEvent @event) { // Confirm or reject stock for each order item foreach (var orderStockItem in @event.OrderStockItems) { var catalogItem = await _context.CatalogItems.FindAsync(orderStockItem.ProductId); var hasStock = catalogItem.AvailableStock >= orderStockItem.Units; // publish OrderStockConfirmedIntegrationEvent or OrderStockRejectedIntegrationEvent } } } ``` -------------------------------- ### Enable Azure OpenAI in Program.cs Source: https://github.com/dotnet/eshop/blob/main/README.md Set this boolean variable to 'true' in 'eShop.AppHost/Program.cs' to enable the Azure OpenAI integration after configuring the connection string in appsettings.json. ```csharp bool useOpenAI = false; ``` -------------------------------- ### Create Catalog Item Source: https://context7.com/dotnet/eshop/llms.txt Creates a new item in the catalog and asynchronously generates an AI embedding for it. ```bash curl -X POST "http://localhost:5222/api/catalog/items?api-version=1.0" \ -H "Content-Type: application/json" \ -d '{ "name": "Alpine Trekking Boot", "description": "Waterproof high-ankle boot for alpine terrain", "price": 149.99, "pictureFileName": "boot.webp", "catalogTypeId": 1, "catalogBrandId": 2, "availableStock": 50, "restockThreshold": 10, "maxStockThreshold": 200 }' # 201 Created — Location: /api/catalog/items/42 ``` -------------------------------- ### Run eShop Application from Terminal Source: https://github.com/dotnet/eshop/blob/main/README.md Execute this command in your terminal to run the eShop application. The output will include a URL to access the Aspire dashboard. ```bash dotnet run --project src/eShop.AppHost/eShop.AppHost.csproj ``` -------------------------------- ### Azure OpenAI Configuration Source: https://github.com/dotnet/eshop/blob/main/README.md To use Azure OpenAI, add this 'ConnectionStrings' section to 'eShop.AppHost/appsettings.json' with your specific endpoint and key. Then, set the 'useOpenAI' flag to true in 'eShop.AppHost/Program.cs'. ```json "ConnectionStrings": { "OpenAi": "Endpoint=xxx;Key=xxx;" } ``` -------------------------------- ### Log in to Azure Developer CLI Source: https://github.com/dotnet/eshop/blob/main/README.md Logs you into your Azure account using the Azure Developer CLI. This is a prerequisite for using `azd` commands. ```sh azd auth login ``` -------------------------------- ### Include Raw Asset in Project Source: https://github.com/dotnet/eshop/blob/main/src/ClientApp/Resources/Raw/AboutAssets.txt Add the MauiAsset build action to include files in your application package. These files are deployed with your package and accessible at runtime. ```xml ``` -------------------------------- ### List Catalog Items (v1) with cURL Source: https://context7.com/dotnet/eshop/llms.txt Use this cURL command to retrieve the first page of catalog items using API version 1.0. Specify `pageSize` and `pageIndex` for pagination. ```bash # List first page of items (v1) curl "http://localhost:5222/api/catalog/items?api-version=1.0&pageSize=10&pageIndex=0" ``` -------------------------------- ### List Payment Card Types Source: https://context7.com/dotnet/eshop/llms.txt Retrieves a list of supported payment card types. ```bash curl "http://localhost:5224/api/orders/cardtypes" \ -H "Authorization: Bearer $TOKEN" ``` -------------------------------- ### List Catalog Item Types Source: https://context7.com/dotnet/eshop/llms.txt Retrieves a list of available catalog item types. ```bash curl "http://localhost:5222/api/catalogtypes?api-version=1.0" # 200 OK → [{"id":1,"type":"Mug"},{"id":2,"type":"T-Shirt"}, ...] ``` -------------------------------- ### Create catalog item Source: https://context7.com/dotnet/eshop/llms.txt Creates a new item in the catalog and asynchronously generates an AI embedding for it. ```APIDOC ## POST /api/catalog/items — Create catalog item ### Description Creates a new item in the catalog and asynchronously generates an AI embedding for it. ### Method POST ### Endpoint /api/catalog/items ### Parameters #### Query Parameters - **api-version** (string) - Required - The API version, e.g., "1.0". #### Request Body - **name** (string) - Required - The name of the catalog item. - **description** (string) - Required - The description of the catalog item. - **price** (number) - Required - The price of the catalog item. - **pictureFileName** (string) - Optional - The filename of the item's picture. - **catalogTypeId** (integer) - Required - The ID of the catalog type. - **catalogBrandId** (integer) - Required - The ID of the catalog brand. - **availableStock** (integer) - Required - The available stock quantity. - **restockThreshold** (integer) - Required - The restock threshold. - **maxStockThreshold** (integer) - Required - The maximum stock threshold. ### Request Example ```json { "name": "Alpine Trekking Boot", "description": "Waterproof high-ankle boot for alpine terrain", "price": 149.99, "pictureFileName": "boot.webp", "catalogTypeId": 1, "catalogBrandId": 2, "availableStock": 50, "restockThreshold": 10, "maxStockThreshold": 200 } ``` ### Response #### Success Response (201 Created) - **Location** header pointing to the created item (e.g., /api/catalog/items/42) ``` -------------------------------- ### CatalogItem Inventory Management Source: https://context7.com/dotnet/eshop/llms.txt Illustrates how to manage stock levels for CatalogItem entities, including removing and adding stock. It highlights the enforcement of business rules, such as preventing stock removal from sold-out items and capping additions at the maximum threshold. ```csharp var item = await context.CatalogItems.FindAsync(7); // item.AvailableStock = 50, item.MaxStockThreshold = 200 // RemoveStock — returns actual units removed (may be less than requested) int removed = item.RemoveStock(quantityDesired: 5); // removed == 5, item.AvailableStock == 45 // RemoveStock on sold-out item item.AvailableStock = 0; item.RemoveStock(1); // throws CatalogDomainException("Empty stock, product item ... is sold out") // AddStock — capped at MaxStockThreshold int added = item.AddStock(quantity: 200); // added == 155 (capped at 200 max), item.OnReorder == false await context.SaveChangesAsync(); ``` -------------------------------- ### Create New Order Source: https://context7.com/dotnet/eshop/llms.txt Submits a new order from the checkout flow. Requires an idempotency key via the `x-requestid` header. The credit card number is masked before being stored. ```bash curl -X POST "http://localhost:5224/api/orders" \ -H "x-requestid: 3fa85f64-5717-4562-b3fc-2c963f66afa6" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "userId": "abc123", "userName": "alice@example.com", "city": "Seattle", "street": "123 Main St", "state": "WA", "country": "US", "zipCode": "98101", "cardNumber": "4111111111111111", "cardHolderName": "Alice Smith", "cardExpiration": "2026-12-01T00:00:00Z", "cardSecurityNumber": "123", "cardTypeId": 1, "buyer": "alice@example.com", "items": [ { "productId": 7, "productName": "Roslyn Shirt", "unitPrice": 12.00, "units": 2 }, { "productId": 14, "productName": "Prism Mug", "unitPrice": 8.50, "units": 1 } ] }' ``` -------------------------------- ### Access Deployed Assets in C# Source: https://github.com/dotnet/eshop/blob/main/src/HybridApp/Resources/Raw/AboutAssets.txt Access deployed assets using `FileSystem.OpenAppPackageFileAsync`. Ensure the file name matches the asset's name in the application package. This method returns a stream that can be read. ```csharp async Task LoadMauiAsset() { using var stream = await FileSystem.OpenAppPackageFileAsync("AboutAssets.txt"); using var reader = new StreamReader(stream); var contents = reader.ReadToEnd(); } ``` -------------------------------- ### List Catalog Item Brands Source: https://context7.com/dotnet/eshop/llms.txt Retrieves a list of available catalog item brands. ```bash curl "http://localhost:5222/api/catalogbrands?api-version=1.0" # 200 OK → [{"id":1,"brand":"Azure"},{"id":2,"brand":".NET"}, ...] ``` -------------------------------- ### Ship an Order Source: https://context7.com/dotnet/eshop/llms.txt Updates the status of an order to 'Shipped'. Requires an idempotency key via the `x-requestid` header. ```bash curl -X PUT "http://localhost:5224/api/orders/ship" \ -H "x-requestid: 9b2e7c9e-1234-5678-abcd-ef1234567890" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "orderNumber": 5 }' ``` -------------------------------- ### List Webhook Subscriptions Source: https://context7.com/dotnet/eshop/llms.txt Retrieves a list of all webhook subscriptions for the authenticated user. ```bash curl "http://localhost:5228/api/webhooks" \ -H "Authorization: Bearer $TOKEN" ``` -------------------------------- ### POST /api/orders/draft Source: https://context7.com/dotnet/eshop/llms.txt Creates an order draft from basket items to calculate totals before checkout confirmation. ```APIDOC ## POST /api/orders/draft — Create order draft ### Description Creates an order draft from basket items to calculate totals before checkout confirmation. ### Method POST ### Endpoint /api/orders/draft ### Parameters #### Headers - **Authorization** (string) - Required - Bearer token for authentication. #### Request Body - **buyerId** (string) - Required - The ID of the buyer. - **items** (array) - Required - A list of items in the basket. - **productId** (integer) - Required - The ID of the product. - **productName** (string) - Required - The name of the product. - **unitPrice** (number) - Required - The price per unit. - **units** (integer) - Required - The quantity of the product. ### Request Example ```json { "buyerId": "abc123", "items": [ { "productId": 7, "productName": "Roslyn Shirt", "unitPrice": 12.00, "units": 2 }, { "productId": 14, "productName": "Prism Mug", "unitPrice": 8.50, "units": 1 } ] } ``` ### Response #### Success Response (200 OK) - Returns an `OrderDraftDTO` with computed order items and total. ``` -------------------------------- ### POST /api/orders Source: https://context7.com/dotnet/eshop/llms.txt Submits a new order from the checkout flow. Requires an idempotency key via the `x-requestid` header. ```APIDOC ## POST /api/orders — Create a new order ### Description Submits a new order from the checkout flow. The credit card number is masked before being stored. Requires an idempotency key via the `x-requestid` header. ### Method POST ### Endpoint /api/orders ### Parameters #### Headers - **x-requestid** (string) - Required - An idempotency key. - **Authorization** (string) - Required - Bearer token for authentication. #### Request Body - **userId** (string) - Required - The ID of the user placing the order. - **userName** (string) - Required - The username or email of the user. - **city** (string) - Required - The city for the shipping address. - **street** (string) - Required - The street address. - **state** (string) - Required - The state or province. - **country** (string) - Required - The country. - **zipCode** (string) - Required - The postal code. - **cardNumber** (string) - Required - The credit card number. - **cardHolderName** (string) - Required - The name of the cardholder. - **cardExpiration** (string) - Required - The expiration date of the card (ISO 8601 format). - **cardSecurityNumber** (string) - Required - The security code of the card. - **cardTypeId** (integer) - Required - The type of the card. - **buyer** (string) - Required - The buyer's email. - **items** (array) - Required - A list of items in the order. - **productId** (integer) - Required - The ID of the product. - **productName** (string) - Required - The name of the product. - **unitPrice** (number) - Required - The price per unit. - **units** (integer) - Required - The quantity of the product. ### Request Example ```json { "userId": "abc123", "userName": "alice@example.com", "city": "Seattle", "street": "123 Main St", "state": "WA", "country": "US", "zipCode": "98101", "cardNumber": "4111111111111111", "cardHolderName": "Alice Smith", "cardExpiration": "2026-12-01T00:00:00Z", "cardSecurityNumber": "123", "cardTypeId": 1, "buyer": "alice@example.com", "items": [ { "productId": 7, "productName": "Roslyn Shirt", "unitPrice": 12.00, "units": 2 }, { "productId": 14, "productName": "Prism Mug", "unitPrice": 8.50, "units": 1 } ] } ``` ### Response #### Success Response (200 OK) - The order is queued via MediatR IdentifiedCommand (idempotent). #### Error Response (400 Bad Request) - "RequestId is missing." if x-requestid header is missing/empty GUID. ``` -------------------------------- ### CatalogAI Service Registration and Usage for Embeddings Source: https://context7.com/dotnet/eshop/llms.txt Details the conditional service registration for CatalogAI, supporting Ollama or OpenAI embeddings. It shows how to generate vector embeddings for catalog items, both individually and in batches, and how to use them for semantic search with pgvector. ```csharp // Service registration in Catalog.API/Extensions/Extensions.cs if (builder.Configuration["OllamaEnabled"] == "true") { builder.AddOllamaApiClient("embedding").AddEmbeddingGenerator(); } else if (!string.IsNullOrWhiteSpace(builder.Configuration.GetConnectionString("textEmbeddingModel"))) { builder.AddOpenAIClientFromConfiguration("textEmbeddingModel").AddEmbeddingGenerator(); } builder.Services.AddScoped(); // appsettings.json (AppHost) — Azure OpenAI connection string // "ConnectionStrings": { "OpenAi": "Endpoint=https://xxx.openai.azure.com/;Key=xxx;" } // Usage — auto-called on item create/update var catalogAI = services.GetRequiredService(); if (catalogAI.IsEnabled) { // Generate embedding for a single item Vector? embedding = await catalogAI.GetEmbeddingAsync(catalogItem); catalogItem.Embedding = embedding; // Batch embeddings during database seeding IReadOnlyList? embeddings = await catalogAI.GetEmbeddingsAsync(catalogItems); } // Semantic query using pgvector cosine distance (inside CatalogApi.GetItemsBySemanticRelevance) var vector = await services.CatalogAI.GetEmbeddingAsync("comfortable running shoe"); var results = await context.CatalogItems .Where(c => c.Embedding != null) .OrderBy(c => c.Embedding!.CosineDistance(vector)) .Take(10) .ToListAsync(); ``` -------------------------------- ### Update Catalog Item (v2) Source: https://context7.com/dotnet/eshop/llms.txt Updates an existing catalog item. If the price changes, a `ProductPriceChangedIntegrationEvent` is published to RabbitMQ atomically with the DB write. ```bash # v2 — id in path (preferred) curl -X PUT "http://localhost:5222/api/catalog/items/42?api-version=2.0" \ -H "Content-Type: application/json" \ -d '{ "id": 42, "name": "Alpine Trekking Boot", "price": 129.99, "catalogTypeId": 1, "catalogBrandId": 2, "availableStock": 45 }' # 201 Created — price change triggers ProductPriceChangedIntegrationEvent on the event bus # v1 — id in body curl -X PUT "http://localhost:5222/api/catalog/items?api-version=1.0" \ -H "Content-Type: application/json" \ -d '{ "id": 42, "name": "Alpine Trekking Boot", "price": 129.99, ... }' ``` -------------------------------- ### POST /api/webhooks Source: https://context7.com/dotnet/eshop/llms.txt Registers a webhook subscription. The service validates the `grantUrl` before persisting. ```APIDOC ## POST /api/webhooks — Subscribe to webhook events ### Description Registers a webhook subscription. The service validates the `grantUrl` before persisting. Supported event types include `CatalogItemPriceChange` and order status events. ### Method POST ### Endpoint /api/webhooks ### Parameters #### Headers - **Authorization** (string) - Required - Bearer token for authentication. #### Request Body - **url** (string) - Required - The URL to send webhook events to. - **grantUrl** (string) - Required - The URL for granting permissions. - **token** (string) - Required - A secret token for the webhook. - **event** (string) - Required - The type of event to subscribe to (e.g., `CatalogItemPriceChange`). ### Request Example ```json { "url": "https://myapp.example.com/hooks/eshop", "grantUrl": "https://myapp.example.com/hooks/eshop/grant", "token": "my-secret-token", "event": "CatalogItemPriceChange" } ``` ### Response #### Success Response (201 Created) - `Location` header contains the URL of the newly created webhook subscription. #### Error Response (400 Bad Request) - "Invalid grant URL: ..." if grant check fails. ``` -------------------------------- ### PUT /api/orders/ship Source: https://context7.com/dotnet/eshop/llms.txt Updates the status of an order to 'Shipped'. Requires an idempotency key. ```APIDOC ## PUT /api/orders/ship — Ship an order ### Description Updates the status of an order to 'Shipped'. Requires an idempotency key. ### Method PUT ### Endpoint /api/orders/ship ### Parameters #### Headers - **x-requestid** (string) - Required - An idempotency key. - **Authorization** (string) - Required - Bearer token for authentication. #### Request Body - **orderNumber** (integer) - Required - The number of the order to ship. ### Request Example ```json { "orderNumber": 5 } ``` ### Response #### Success Response (200 OK) - Order status set to Shipped. #### Error Response (500 Problem) - "ship failed" ``` -------------------------------- ### Filter Catalog Items (v2) with cURL Source: https://context7.com/dotnet/eshop/llms.txt This cURL command demonstrates filtering catalog items by name, type, and brand using API version 2.0. Ensure `pageSize` and `pageIndex` are set for pagination. ```bash # Filter by name, type, and brand (v2 only) curl "http://localhost:5222/api/catalog/items?api-version=2.0&name=Shirt&type=2&brand=3&pageSize=5&pageIndex=0" ``` -------------------------------- ### Subscribe to Webhook Events Source: https://context7.com/dotnet/eshop/llms.txt Registers a webhook subscription. The service validates the `grantUrl` before persisting. Supported event types include `CatalogItemPriceChange` and order status events. ```bash curl -X POST "http://localhost:5228/api/webhooks" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "url": "https://myapp.example.com/hooks/eshop", "grantUrl": "https://myapp.example.com/hooks/eshop/grant", "token": "my-secret-token", "event": "CatalogItemPriceChange" }' ``` -------------------------------- ### Generate Vector Embeddings for Catalog Items Source: https://context7.com/dotnet/eshop/llms.txt Generates 384-dimension vector embeddings for catalog items using OpenAI or Ollama models, enabling semantic search. The service registers conditionally and falls back gracefully. ```APIDOC ## CatalogAI — Semantic Embedding Service ### `ICatalogAI.GetEmbeddingAsync` — Generate vector embeddings for catalog items Wraps OpenAI or Ollama embedding models (384-dimension vectors) to power semantic search via pgvector. Registers conditionally—falls back gracefully when AI is not configured. ```csharp // Service registration in Catalog.API/Extensions/Extensions.cs if (builder.Configuration["OllamaEnabled"] == "true") { builder.AddOllamaApiClient("embedding").AddEmbeddingGenerator(); } else if (!string.IsNullOrWhiteSpace(builder.Configuration.GetConnectionString("textEmbeddingModel"))) { builder.AddOpenAIClientFromConfiguration("textEmbeddingModel").AddEmbeddingGenerator(); } builder.Services.AddScoped(); // appsettings.json (AppHost) — Azure OpenAI connection string // "ConnectionStrings": { "OpenAi": "Endpoint=https://xxx.openai.azure.com/;Key=xxx;" } // Usage — auto-called on item create/update var catalogAI = services.GetRequiredService(); if (catalogAI.IsEnabled) { // Generate embedding for a single item Vector? embedding = await catalogAI.GetEmbeddingAsync(catalogItem); catalogItem.Embedding = embedding; // Batch embeddings during database seeding IReadOnlyList? embeddings = await catalogAI.GetEmbeddingsAsync(catalogItems); } // Semantic query using pgvector cosine distance (inside CatalogApi.GetItemsBySemanticRelevance) var vector = await services.CatalogAI.GetEmbeddingAsync("comfortable running shoe"); var results = await context.CatalogItems .Where(c => c.Embedding != null) .OrderBy(c => c.Embedding!.CosineDistance(vector)) .Take(10) .ToListAsync(); ``` ``` -------------------------------- ### List item types Source: https://context7.com/dotnet/eshop/llms.txt Retrieves a list of available catalog item types. ```APIDOC ## GET /api/catalogtypes — List item types ### Description Retrieves a list of available catalog item types. ### Method GET ### Endpoint /api/catalogtypes ### Parameters #### Query Parameters - **api-version** (string) - Required - The API version, e.g., "1.0". ### Response #### Success Response (200 OK) - An array of catalog type objects, each with an `id` and `type` field. Example: `[{"id":1,"type":"Mug"},{"id":2,"type":"T-Shirt"}, ...] ` ``` -------------------------------- ### CatalogItem Inventory Management Source: https://context7.com/dotnet/eshop/llms.txt Manages stock levels for `CatalogItem` entities, enforcing business rules and throwing `CatalogDomainException` for invalid operations. Stock additions are capped at `MaxStockThreshold`. ```APIDOC ## CatalogItem — Domain Model ### `CatalogItem.RemoveStock` / `AddStock` — Inventory management The `CatalogItem` entity enforces business rules around stock levels, throwing `CatalogDomainException` on invalid operations. ```csharp var item = await context.CatalogItems.FindAsync(7); // item.AvailableStock = 50, item.MaxStockThreshold = 200 // RemoveStock — returns actual units removed (may be less than requested) int removed = item.RemoveStock(quantityDesired: 5); // removed == 5, item.AvailableStock == 45 // RemoveStock on sold-out item item.AvailableStock = 0; item.RemoveStock(1); // throws CatalogDomainException("Empty stock, product item ... is sold out") // AddStock — capped at MaxStockThreshold int added = item.AddStock(quantity: 200); // added == 155 (capped at 200 max), item.OnReorder == false await context.SaveChangesAsync(); ``` ```