### Install Composable Commerce .NET SDK Packages Source: https://context7.com/commercetools/commercetools-dotnet-core-sdk-v2/llms.txt Install the necessary NuGet packages for the Composable Commerce HTTP API, Import API, Change History API, or the optional GraphQL client. ```bash dotnet add package commercetools.Sdk.Api # Import API dotnet add package commercetools.Sdk.ImportApi # Change History API dotnet add package commercetools.Sdk.HistoryApi # Type-safe GraphQL client (optional add-on) dotnet add package commercetools.Sdk.GraphQL.Api ``` -------------------------------- ### Setup Multiple Commercetools Clients Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/README.md Configure multiple commercetools clients within the same application, each potentially using a different token provider. This example demonstrates setting up two clients with the default ClientCredentials token provider. ```csharp services.UseCommercetoolsApi(configuration, new List{"AdminClient", "StoreClient"}, CreateTokenProvider); public static ITokenProvider CreateTokenProvider(string clientName, IConfiguration configuration, IServiceProvider serviceProvider) { var httpClientFactory = serviceProvider.GetService(); var clientConfiguration = configuration.GetSection(clientName).Get(); return TokenProviderFactory.CreateClientCredentialsTokenProvider(clientConfiguration, httpClientFactory); } ``` -------------------------------- ### Run Dockerized Application with New Relic Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/commercetools.Sdk/Examples/commercetools.Api.NewRelicExample/README.md Execute the provided Dockerfile to build and run the example application with the New Relic agent installed. Ensure you replace the placeholder with your New Relic license key. ```shell docker run --rm --port 8080:80 --env NEW_RELIC_LICENSE_KEY= ``` -------------------------------- ### Setup Client with Default Handlers Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/README.md Shows how to use the SetupClient extension method when building the services container to attach default handlers like ErrorHandler and LoggerHandler to the client. ```csharp services.SetupClient( "MeClient", errorTypeMapper => typeof(ErrorResponse), s => s.GetService() ); ``` -------------------------------- ### CRUD Operations via ProjectApiRoot - Categories Example Source: https://context7.com/commercetools/commercetools-dotnet-core-sdk-v2/llms.txt Illustrates how to perform Create, Read (by ID and Key), Update, and Delete operations on resources using the ProjectApiRoot and the builder pattern, using categories as an example. ```APIDOC ## CRUD operations via `ProjectApiRoot` — categories example All resources follow the same builder pattern. `Post(draft)` creates, `WithId(id).Get()` retrieves by ID, `WithKey(key).Get()` retrieves by key, `WithId(id).Post(update)` updates, and `WithId(id).Delete().WithVersion(v)` deletes. ```csharp // CREATE var draft = new CategoryDraft { Name = new LocalizedString { { "en", "Summer Sale" } }, Slug = new LocalizedString { { "en", "summer-sale" } }, Key = "summer-sale-2024" }; var category = await projectRoot.Categories().Post(draft).ExecuteAsync(); // GET BY ID var byId = await projectRoot.Categories().WithId(category.Id).Get().ExecuteAsync(); // GET BY KEY var byKey = await projectRoot.Categories().WithKey("summer-sale-2024").Get().ExecuteAsync(); // QUERY with sorting, limit, and expand var page = await projectRoot.Categories() .Get() .WithWhere($"key = \"{category.Key}\"") .WithSort("name.en asc") .WithLimit(20) .WithOffset(0) .WithWithTotal(true) .WithExpand("parent") .ExecuteAsync(); Console.WriteLine(page.Total); // total count // UPDATE var update = new CategoryUpdate { Version = category.Version, Actions = new List { new CategoryChangeNameAction { Name = new LocalizedString { { "en", "Winter Sale" } } } } }; var updated = await projectRoot.Categories().WithKey("summer-sale-2024").Post(update).ExecuteAsync(); // DELETE BY ID await projectRoot.Categories() .WithId(category.Id) .Delete() .WithVersion(updated.Version) .ExecuteAsync(); ``` ``` -------------------------------- ### Setup Change History API with Dependency Injection Source: https://context7.com/commercetools/commercetools-dotnet-core-sdk-v2/llms.txt Use `UseCommercetoolsHistoryApi` in `Startup.cs` to register the Change History API client. Configuration is provided via `appsettings.json`. The `HistoryProjectApiRoot` can then be injected into controllers for usage. ```csharp // Startup.cs services.UseCommercetoolsHistoryApi(configuration, "HistoryClient"); ``` ```json // appsettings.json { "HistoryClient": { "ClientId": "history-client-id", "ClientSecret": "history-client-secret", "AuthorizationBaseAddress": "https://auth.europe-west1.gcp.commercetools.com/", "Scope": "view_audit_log:my-project-key", "ProjectKey": "my-project-key", "ApiBaseAddress": "https://history.europe-west1.gcp.commercetools.com/" } } ``` ```csharp // Usage via injected HistoryProjectApiRoot using HistoryProjectApiRoot = commercetools.Sdk.HistoryApi.Client.ProjectApiRoot; public class HistoryController(HistoryProjectApiRoot historyRoot) { public async Task QueryChanges() { var changes = await historyRoot.WithProjectKey("my-project-key") .Get() .ExecuteAsync(); // process change records } } ``` -------------------------------- ### Install HTTP API Package (V1) Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/docs/COMPARISON.md Use this command to add the commercetools SDK V1 package, which includes the HTTP API. ```dotnet dotnet add package commercetools.Sdk.All ``` -------------------------------- ### Install Import API Package (V2) Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/docs/COMPARISON.md Use this command to add the commercetools SDK V2 package for the Import API. ```dotnet dotnet add package commercetools.Sdk.ImportApi ``` -------------------------------- ### Create and Execute SDK Requests Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/README.md Demonstrates creating and executing various requests for the Category resource using the SDK's builder pattern. Includes creating, getting by ID and key, querying, updating, and deleting categories. ```csharp private readonly IClient client; public CategoryController(IClient client) { this.client = client; } public async Task CreatingRequests() { var projectApiRoot = client.WithProject("project-key") // Create CategoryDraft var categoryDraft = new CategoryDraft { Name = new LocalizedString {{"en", "Name"}}, Slug = new LocalizedString {{"en", "Slug"}}, Key = "Key" }; // Use in the previous step configured client instance to send and receive a newly created Category var category = await projectApiRoot .Categories() .Post(categoryDraft) .ExecuteAsync(); // Get Category by id var queriedCategory = await projectApiRoot .Categories() .WithId(category.Id) .Get() .ExecuteAsync(); // Get Category by key var queriedCategory = await projectApiRoot .Categories() .WithKey(category.Key) .Get() .ExecuteAsync(); // Query Categories var response = await projectApiRoot .Categories() .Get() .WithWhere($"key = \"{category.Key}\"") .ExecuteAsync(); // Delete Category by id var deletedCategory = await projectApiRoot .Categories() .WithId(category.Id) .Delete() .WithVersion(category.version) .ExecuteAsync(); // Update Category var newName = "newName"; var action = new CategoryChangeNameAction { Name = new LocalizedString {{"en", newName}} }; var update = new CategoryUpdate { Version = category.Version, Actions = new List {action} }; var updatedCategory = await projectApiRoot .Categories() .WithId(category.Id) .Post(categoryUpdate) .ExecuteAsync(); // Delete Category by key var deletedCategory = await projectApiRoot .Categories() .WithKey(category.Key) .Delete() .WithVersion(category.Version) .ExecuteAsync(); } ``` -------------------------------- ### Install HTTP API Package (V2) Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/docs/COMPARISON.md Use this command to add the commercetools SDK V2 package for the HTTP API. ```dotnet dotnet add package commercetools.Sdk.Api ``` -------------------------------- ### Install Machine Learning API Package (V2) Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/docs/COMPARISON.md Use this command to add the commercetools SDK V2 package for the Machine Learning API. ```dotnet dotnet add package commercetools.Sdk.MLApi ``` -------------------------------- ### Install Change History API Package (V2) Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/docs/COMPARISON.md Use this command to add the commercetools SDK V2 package for the Change History API. ```dotnet dotnet add package commercetools.Sdk.HistoryApi ``` -------------------------------- ### Get Category By Key: V2 vs V1 SDK in C# Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/docs/COMPARISON.md Illustrates fetching a category by its key. The V2 SDK uses '.Categories().WithKey(category.Key).Get()', whereas the V1 SDK employs '.Builder().Categories().GetByKey(category.Key)'. ```csharp var queriedCategory = await projectApiRoot .Categories() .WithKey(category.Key) .Get() .ExecuteAsync(); ``` ```csharp var queriedCategory = await client .Builder() .Categories() .GetByKey(category.Key) .ExecuteAsync(); ``` -------------------------------- ### Build Customer Query Predicates Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/docs/Predicates.md Use predicate builders to construct type-safe queries for customer resources. Examples include exact matches, inequality, and version comparisons. ```csharp // name = "Peter" // For exact match to "Peter". This does not perform substring match. _projectApiRoot.Customers().Get() .WithQuery(q => q.FirstName().Is("Peter")); // firstName != "Peter" _projectApiRoot.Customers().Get() .WithQuery(q => q.FirstName().IsNot("Peter")); // version < 42 _projectApiRoot.Customers().Get() .WithQuery(q => q.Version().IsLessThan(42)); // version > 42 _projectApiRoot.Customers().Get() .WithQuery(q => q.Version().IsGreaterThan(42)); // version <= 42 _projectApiRoot.Customers().Get() .WithQuery(q => q.Version().IsLessThanOrEqual(42)); // version >= 42 _projectApiRoot.Customers().Get() .WithQuery(q => q.Version().IsGreaterThanOrEqual(42)); // version <> 42 _projectApiRoot.Customers().Get() .WithQuery(q => q.Version().IsNot(42)); ``` -------------------------------- ### Create Category: V2 vs V1 SDK in C# Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/docs/COMPARISON.md Compares the methods for creating a category using the V2 and V1 SDKs. The V2 SDK uses a fluent API starting with '.Categories().Post()', while V1 uses '.Builder().Categories().Create()'. ```csharp var category = await projectApiRoot .Categories() .Post(categoryDraft) .ExecuteAsync(); ``` ```csharp var category = await client .Builder() .Categories() .Create(categoryDraft) .ExecuteAsync(); ``` -------------------------------- ### Get ProjectApiRoot Instance for Specific Project Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/README.md Instantiate a ProjectApiRoot, which is scoped to a project key, simplifying request building. This can be done via the injected client or the ApiFactory. ```csharp ProjectApiRoot root1 = client.WithProject(projectKey); ProjectApiRoot root2 = ApiFactory.Create(client, projectKey); ``` ```csharp ProjectApiRoot root1 = client.WithImportApi(projectKey); ProjectApiRoot root2 = ImportApiFactory.Create(client, projectKey); ``` ```csharp ProjectApiRoot root1 = client.WithHistoryApi(projectKey); ProjectApiRoot root2 = HistoryApiFactory.Create(client, projectKey); ``` -------------------------------- ### Programmatic Client Construction with ClientBuilder Source: https://context7.com/commercetools/commercetools-dotnet-core-sdk-v2/llms.txt Construct an `IClient` instance manually using `ClientBuilder`. This is suitable for console applications or services requiring dynamic token flow management. Ensure `UseCommercetoolsApiSerialization` and `SetupClient` are called during service collection setup. ```csharp using commercetools.Base.Client; using commercetools.Sdk.Api; using commercetools.Sdk.Api.Serialization; using Microsoft.Extensions.DependencyInjection; // Minimal console app bootstrapping var services = new ServiceCollection(); services.UseCommercetoolsApiSerialization(); services.AddLogging(); services.SetupClient("MyClient", _ => typeof(ErrorResponse), sp => sp.GetRequiredService()); var provider = services.BuildServiceProvider(); var config = new ClientConfiguration { ClientId = "my-client-id", ClientSecret = "my-client-secret", ProjectKey = "my-project-key", ApiBaseAddress = "https://api.europe-west1.gcp.commercetools.com/", AuthorizationBaseAddress = "https://auth.europe-west1.gcp.commercetools.com/" }; var httpFactory = provider.GetRequiredService(); var client = new ClientBuilder { ClientName = "MyClient", ClientConfiguration = config, TokenProvider = TokenProviderFactory.CreateClientCredentialsTokenProvider(config, httpFactory), SerializerService = provider.GetRequiredService(), HttpClient = httpFactory.CreateClient("MyClient") }.Build(); var project = await new ApiRoot(client).WithProjectKey(config.ProjectKey).Get().ExecuteAsync(); Console.WriteLine(project.Name); // "My Project" ``` -------------------------------- ### Get ApiRoot Instance for Commercetools APIs Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/README.md Obtain an ApiRoot instance for interacting with different commercetools APIs. You can use the injected client or the ApiFactory for creation. ```csharp var root1 = client.WithApi(); var root2 = ApiFactory.Create(client); ``` ```csharp var root1 = client.WithImportApi(); var root2 = ImportApiFactory.Create(client); ``` ```csharp var root1 = client.WithHistoryApi(); var root2 = HistoryApiFactory.Create(client); ``` -------------------------------- ### Get Category By ID: V2 vs V1 SDK in C# Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/docs/COMPARISON.md Demonstrates retrieving a category by its ID using both V2 and V1 SDKs. V2 uses '.Categories().WithId(category.Id).Get()', while V1 uses '.Builder().Categories().GetById(category.Id)'. ```csharp var queriedCategory = await projectApiRoot .Categories() .WithId(category.Id) .Get() .ExecuteAsync(); ``` ```csharp var queriedCategory = await client .Builder() .Categories() .GetById(category.Id) .ExecuteAsync(); ``` -------------------------------- ### Client Initialization and Me API Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/README.md Demonstrates how to create an SDK client using the ClientFactory and access the 'Me' API for customer-specific operations. ```APIDOC ## Create Client with ClientFactory ### Description Initializes an SDK client using the `ClientFactory`, suitable for accessing customer-specific APIs like 'Me'. This example uses the Password Token Flow. ### Method Factory Method ### Usage ```csharp // Assuming IServiceProvider, IConfiguration, IHttpClientFactory, SerializerService are available var configuration = serviceProvider.GetService(); var httpClientFactory = serviceProvider.GetService(); var serializerService = serviceProvider.GetService(); var clientConfiguration = configuration.GetSection("MeClient").Get(); // Create passwordFlow TokenProvider var passwordTokenProvider = TokenProviderFactory .CreatePasswordTokenProvider(clientConfiguration, httpClientFactory, new InMemoryUserCredentialsStoreManager(email, password)); // Create MeClient var meClient = ClientFactory.Create( "MeClient", clientConfiguration, httpClientFactory, serializerService, passwordTokenProvider); ``` ## Get My Profile ### Description Retrieves the profile information for the currently authenticated customer. ### Method GET ### Endpoint /me ### Usage ```csharp var myProfile = await meClient.WithApi().WithProjectKey("project-key") .Me() .Get() .ExecuteAsync(); ``` ### Response #### Success Response (200 OK) - **MyProfile** (MyProfile) - The customer's profile information. ## Get My Orders ### Description Retrieves a list of orders for the currently authenticated customer. ### Method GET ### Endpoint /me/orders ### Usage ```csharp var myOrders = await meClient.WithApi() .WithProjectKey("project-key") .Me() .Orders() .Get() .ExecuteAsync(); ``` ### Response #### Success Response (200 OK) - **OrderQueryResponse** (OrderQueryResponse) - A response object containing a list of the customer's orders. ## SDK Service Setup ### Description Configures the SDK client with default handlers like ErrorHandler and LoggerHandler when setting up services. ### Usage ```csharp services.SetupClient( "MeClient", errorTypeMapper => typeof(ErrorResponse), s => s.GetService() ); ``` ``` -------------------------------- ### Create Client with ClientFactory and TokenFlow Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/README.md Illustrates creating a client instance on the fly using ClientFactory with password TokenFlow for accessing customer orders. Requires configuration, HttpClientFactory, and SerializerService. ```csharp private readonly IServiceProvider serviceProvider; public CustomerController(IServiceProvider serviceProvider) { this.serviceProvider = serviceProvider; } public async Task ExecuteAsync() { var email = "customerEmail"; var password = "customerPassword"; var configuration = serviceProvider.GetService(); var httpClientFactory = serviceProvider.GetService(); var serializerService = serviceProvider.GetService(); var clientConfiguration = configuration.GetSection("MeClient").Get(); //Create passwordFlow TokenProvider var passwordTokenProvider = TokenProviderFactory .CreatePasswordTokenProvider(clientConfiguration, httpClientFactory, new InMemoryUserCredentialsStoreManager(email, password)); //Create MeClient var meClient = ClientFactory.Create( "MeClient", clientConfiguration, httpClientFactory, serializerService, passwordTokenProvider); //Get Customer Profile var myProfile = await meClient.WithApi().WithProjectKey("project-key") .Me() .Get() .ExecuteAsync(); //Get Customer Orders var myOrders = await meClient.WithApi() .WithProjectKey("project-key") .Me() .Orders() .Get() .ExecuteAsync(); } ``` -------------------------------- ### Get Category By ID Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/docs/COMPARISON.md Compares the V2 and V1 SDK methods for retrieving a category by its ID. ```APIDOC ## Get Category By ID ### Description Retrieves a category by its unique identifier. ### V2 SDK Example ```csharp var queriedCategory = await projectApiRoot .Categories() .WithId(category.Id) .Get() .ExecuteAsync(); ``` ### V1 SDK Example ```csharp var queriedCategory = await client .Builder() .Categories() .GetById(category.Id) .ExecuteAsync(); ``` ``` -------------------------------- ### Configure HTTP API with Dependency Injection Source: https://context7.com/commercetools/commercetools-dotnet-core-sdk-v2/llms.txt Set up the HTTP API client and ProjectApiRoot in ASP.NET Core using `UseCommercetoolsApi`. Ensure client configuration in `appsettings.json` matches the provided section name. ```csharp // Startup.cs / Program.cs services.UseCommercetoolsApi(configuration, "Client"); // appsettings.json { "Client": { "ClientId": "my-client-id", "ClientSecret": "my-client-secret", "AuthorizationBaseAddress": "https://auth.europe-west1.gcp.commercetools.com/", "Scope": "manage_project:my-project-key", "ProjectKey": "my-project-key", "ApiBaseAddress": "https://api.europe-west1.gcp.commercetools.com/" } } // Controller usage after DI setup public class ProjectController(ProjectApiRoot projectApiRoot) { public async Task GetProjectName() { var project = await projectApiRoot.Get().ExecuteAsync(); return project.Name; // "My Project" } } ``` -------------------------------- ### Get Category By Key Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/docs/COMPARISON.md Compares the V2 and V1 SDK methods for retrieving a category by its key. ```APIDOC ## Get Category By Key ### Description Retrieves a category by its unique key. ### V2 SDK Example ```csharp var queriedCategory = await projectApiRoot .Categories() .WithKey(category.Key) .Get() .ExecuteAsync(); ``` ### V1 SDK Example ```csharp var queriedCategory = await client .Builder() .Categories() .GetByKey(category.Key) .ExecuteAsync(); ``` ``` -------------------------------- ### Initialize GraphQL Client with ZeroQL Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/docs/GraphQL.md Instantiate the GraphQL client for type-safe queries using ZeroQL. This client simplifies GraphQL operations by generating query builders. ```csharp var client = _projectApiRoot.GraphQLClient(); var variables = new { productFilter = $"id = \"{productId}\"" }; var response = await client.Query(variables, static (i, o) => o.Products(where: i.productFilter, selector: r => new { results = r.Results(product => new { product.Id }) })); ``` -------------------------------- ### Configure Import API with Dependency Injection Source: https://context7.com/commercetools/commercetools-dotnet-core-sdk-v2/llms.txt Register the Import API client and its ProjectApiRoot using `UseCommercetoolsImportApi`. The Import API is suitable for bulk importing resources. Configuration details should be provided in `appsettings.json`. ```csharp // Startup.cs services.UseCommercetoolsImportApi(configuration, "ImportClient"); // appsettings.json { "ImportClient": { "ClientId": "import-client-id", "ClientSecret": "import-client-secret", "AuthorizationBaseAddress": "https://auth.europe-west1.gcp.commercetools.com/", "Scope": "manage_import_containers:my-project-key", "ProjectKey": "my-project-key", "ApiBaseAddress": "https://import.europe-west1.gcp.commercetools.com/" } } // Usage via injected ImportProjectApiRoot using ImportProjectApiRoot = commercetools.Sdk.ImportApi.Client.ProjectApiRoot; public class ImportController(ImportProjectApiRoot importRoot) { public async Task GetContainers() { var containers = await importRoot.ImportContainers().Get().ExecuteAsync(); return containers; // contains list of import containers } } ``` -------------------------------- ### Create API Roots using ApiFactory and IClient Extensions Source: https://context7.com/commercetools/commercetools-dotnet-core-sdk-v2/llms.txt Use `ApiFactory` or extension methods on `IClient` to create `ApiRoot` and `ProjectApiRoot` instances from an existing `IClient`. This allows for easy creation of project-scoped or store-scoped request builders. ```csharp // Create a project-scoped root ProjectApiRoot projectRoot = ApiFactory.Create(client, "my-project-key"); // Create a store-scoped request builder var storeBuilder = ApiFactory.CreateForStore(client, "my-project-key", "my-store-key"); // Use extension methods on IClient ApiRoot apiRoot = client.WithApi(); ProjectApiRoot projectRoot2 = client.WithProject("my-project-key"); // Execute a project-level GET var project = await projectRoot.Get().ExecuteAsync(); Console.WriteLine(project.Key); // "my-project-key" ``` -------------------------------- ### Configure Machine Learning API Service (V2) Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/docs/COMPARISON.md Configure the commercetools Machine Learning API service using dependency injection in V2. ```csharp services.UseCommercetoolsMLApi(this.configuration, "MLClient"); ``` -------------------------------- ### Configure HTTP API Service (V1) Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/docs/COMPARISON.md Configure the commercetools HTTP API service using dependency injection in V1. ```csharp services.UseCommercetools( ``` ```csharp this.configuration,"Client"); ``` -------------------------------- ### Configure Client Settings in appsettings.json Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/README.md Define the client credentials and API endpoints in your appsettings.json file. Replace placeholder values with your actual credentials and desired base addresses. ```json { "Client": { "ClientId": "", // replace with your client ID "ClientSecret": "", // replace with your client secret "AuthorizationBaseAddress": "https://auth.europe-west1.gcp.commercetools.com/", // replace if needed "Scope": "", // replace with your scope "ProjectKey": "", // replace with your project key "ApiBaseAddress": "https://api.europe-west1.gcp.commercetools.com/" // replace if needed } } ``` -------------------------------- ### Multiple Clients - Registering Several Clients Source: https://context7.com/commercetools/commercetools-dotnet-core-sdk-v2/llms.txt Shows how to register multiple named IClient instances with different configurations or token providers in a DI container, allowing them to be injected as IEnumerable. ```APIDOC ## Multiple clients — registering several clients in one application Multiple named `IClient` instances with different configurations or token providers can be registered in the same DI container and injected as `IEnumerable`. ```csharp // Startup.cs services.UseCommercetoolsApi( configuration, new List { "AdminClient", "StoreClient" }, CreateTokenProvider); static ITokenProvider CreateTokenProvider( string clientName, IConfiguration cfg, IServiceProvider sp) { var factory = sp.GetRequiredService(); var clientCfg = cfg.GetSection(clientName).Get(); return TokenProviderFactory.CreateClientCredentialsTokenProvider(clientCfg, factory); } // Controller injection public class OrderController(IEnumerable clients) { private readonly IClient _store = clients.First(c => c.Name == "StoreClient"); public async Task GetOrders() => await _store.WithProject("my-project-key").Orders().Get().ExecuteAsync(); } ``` ``` -------------------------------- ### Configure HTTP API Service (V2) Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/docs/COMPARISON.md Configure the commercetools HTTP API service using dependency injection in V2. ```csharp services.UseCommercetoolsApi(this.configuration, "Client"); ``` -------------------------------- ### Create OAuth2 Token Providers with TokenProviderFactory Source: https://context7.com/commercetools/commercetools-dotnet-core-sdk-v2/llms.txt Demonstrates creating token providers for client credentials, password, and anonymous session flows. Each provider caches tokens and refreshes them automatically. Use these interchangeably with ClientBuilder. ```csharp // 1. Client credentials flow (machine-to-machine) var ccProvider = TokenProviderFactory.CreateClientCredentialsTokenProvider(config, httpFactory); // 2. Password flow (on behalf of a customer) var userStore = new InMemoryUserCredentialsStoreManager("customer@example.com", "s3cr3t"); var pwProvider = TokenProviderFactory.CreatePasswordTokenProvider(config, httpFactory, userStore); // 3. Anonymous session flow (guest checkout) var anonStore = new InMemoryAnonymousCredentialsStoreManager(); anonStore.AnonymousId = Guid.NewGuid().ToString(); var anonProvider = TokenProviderFactory.CreateAnonymousSessionTokenProvider(config, httpFactory, anonStore); // Build a Me-client using password flow var meClient = new ClientBuilder { ClientName = "MeClient", ClientConfiguration = config, TokenProvider = pwProvider, SerializerService = serializerService, HttpClient = httpFactory.CreateClient("MeClient") }.Build(); var myProfile = await meClient.WithApi() .WithProjectKey("my-project-key") .Me() .Get() .ExecuteAsync(); Console.WriteLine(myProfile.Email); // "customer@example.com" ``` -------------------------------- ### Use Type-Safe GraphQL Client with ZeroQL in C# Source: https://context7.com/commercetools/commercetools-dotnet-core-sdk-v2/llms.txt Leverage the commercetools.Sdk.GraphQL.Api package for a strongly-typed GraphQL experience using ZeroQL. Results are mapped directly to .NET types. ```csharp using commercetools.Sdk.GraphQL.Api; // Obtain the typed GraphQL client from ProjectApiRoot var gqlClient = projectRoot.GraphQLClient(); // Execute a typed query with variables and a projection selector var variables = new { productFilter = $"id = \"{productId}\"" }; var result = await gqlClient.Query( variables, static (i, o) => o.Products( where: i.productFilter, selector: r => new { results = r.Results(p => new { p.Id, p.Version }) })); if (result.Errors is null) { Console.WriteLine(result.Data?.results[0].Id); // "product-uuid" Console.WriteLine(result.Data?.results[0].Version); // 3 } else { foreach (var err in result.Errors) Console.WriteLine(err.Message); } ``` -------------------------------- ### Configure OpenTelemetry Exporters Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/commercetools.Sdk/Examples/commercetools.Api.CheckoutApp/README.md Configure the appsettings.json file to export logs, metrics, and traces using OpenTelemetry. Setting exporter options to 'otlp' sends data to a local OTLP endpoint. ```json { "UseLogExporter": "otlp", "UseTracingExporter": "otlp", "UseMetricExporter": "otlp" } ``` -------------------------------- ### Scoped Operations for Stores and Business Units Source: https://context7.com/commercetools/commercetools-dotnet-core-sdk-v2/llms.txt Utilize `InStore(storeKey)` and `InBusinessUnit(buKey)` on `ProjectApiRoot` to prefix requests with store or business unit paths for multi-store or B2B scenarios. `ApiFactory` can also be used to create store-specific builders. ```csharp // All operations on a specific store var storeRoot = projectRoot.InStore("us-east-store"); // Create a cart inside the store context var cart = await storeRoot.Carts() .Post(new CartDraft { Currency = "USD" }) .ExecuteAsync(); // Query orders within the store var orders = await storeRoot.Orders() .Get() .WithWhere($"customerId = \"{customerId}\") .ExecuteAsync(); // In-business-unit (B2B) scoped operations var buRoot = projectRoot.InBusinessUnit("acme-corp"); var buOrders = await buRoot.Orders().Get().ExecuteAsync(); // Using ApiFactory directly for a store builder var storeBuilder = ApiFactory.CreateForStore(client, "my-project-key", "us-east-store"); var customers = await storeBuilder.Customers().Get().ExecuteAsync(); ``` -------------------------------- ### Configure Import API Service (V2) Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/docs/COMPARISON.md Configure the commercetools Import API service using dependency injection in V2. ```csharp services.UseCommercetoolsImportApi(this.configuration, "ImportClient"); ``` -------------------------------- ### Configure ClientOptions for HTTP Client Behavior Source: https://context7.com/commercetools/commercetools-dotnet-core-sdk-v2/llms.txt Tune HTTP client behavior like compression, HTTP version, and 404 handling using ClientOptions. These options can be passed during service registration or directly to ClientBuilder. ```csharp var options = new ClientOptions { DecompressionMethods = DecompressionMethods.GZip | DecompressionMethods.Deflate, ReadResponseAsStream = true, // uses StreamCtpClient for lower memory usage NotFoundReturnsDefault = false, // throw NotFoundException on 404 (default) HeadNotFoundReturnsDefault = true, // return null on HEAD 404 (existence checks) UseHttpVersion = HttpVersion.Version20 // HTTP/2 (default) }; services.UseCommercetoolsApi(configuration, "Client", options: options); // Or pass directly to ClientBuilder indirectly via SetupClient: services.SetupClient("Client", _ => typeof(ErrorResponse), sp => sp.GetRequiredService(), options); ``` -------------------------------- ### Direct GraphQL POST Request Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/docs/GraphQL.md This snippet demonstrates how to make a direct POST request to the GraphQL endpoint using the SDK. It shows how to construct a GraphQLRequest with a query and variables, execute it, and assert the response data structure. ```APIDOC ## Direct GraphQL POST Request ### Description This example shows how to send a raw GraphQL query to the endpoint using the SDK's `Graphql().Post()` method. It includes setting the query string and variables, executing the request asynchronously, and basic assertions on the JSON response. ### Method POST ### Endpoint `/graphql` (Implied by `_projectApiRoot.Graphql().Post()`) ### Request Body - **query** (string) - Required - The GraphQL query string. - **variables** (GraphQLVariablesMap) - Optional - A map of variables for the query. ### Request Example ```csharp IGraphQLResponse response = await _projectApiRoot.Graphql().Post(new GraphQLRequest() { Query = "query($productFilter:String) { products(where: $productFilter) { results { id } } }", Variables = new GraphQLVariablesMap() { {"productFilter", "id = \"" + product.getId() + "\""} } }) .ExecuteAsync(); ``` ### Response #### Success Response (200) - **data** (JsonElement) - The data returned by the GraphQL query. #### Response Example ```csharp Assert.IsType(response.Data); Assert.IsType(((JsonElement)response.Data).GetProperty("products").GetProperty("results")[0].GetProperty("id").GetString()); ``` ``` -------------------------------- ### Register Multiple Clients in DI Container Source: https://context7.com/commercetools/commercetools-dotnet-core-sdk-v2/llms.txt Shows how to register multiple named IClient instances with different configurations or token providers in a DI container. These clients can then be injected as IEnumerable. ```csharp // Startup.cs services.UseCommercetoolsApi( configuration, new List { "AdminClient", "StoreClient" }, CreateTokenProvider); static ITokenProvider CreateTokenProvider( string clientName, IConfiguration cfg, IServiceProvider sp) { var factory = sp.GetRequiredService(); var clientCfg = cfg.GetSection(clientName).Get(); return TokenProviderFactory.CreateClientCredentialsTokenProvider(clientCfg, factory); } // Controller injection public class OrderController(IEnumerable clients) { private readonly IClient _store = clients.First(c => c.Name == "StoreClient"); public async Task GetOrders() => await _store.WithProject("my-project-key").Orders().Get().ExecuteAsync(); } ``` -------------------------------- ### Configure NotFoundMiddleware for 404 Handling Source: https://context7.com/commercetools/commercetools-dotnet-core-sdk-v2/llms.txt Add NotFoundMiddleware to the pipeline to convert NotFoundException to a 404 HttpResponseMessage instead of throwing. Useful for checking resource existence. ```csharp var client = new ClientBuilder { ClientName = "Client", ClientConfiguration = config, TokenProvider = tokenProvider, SerializerService = serializerService, HttpClient = httpFactory.CreateClient("Client"), Middlewares = new[] { new NotFoundMiddleware() } }.Build(); // Returns null instead of throwing NotFoundException var category = await client.WithProject("my-project-key") .Categories() .WithId("does-not-exist") .Get() .ExecuteAsync(); // null when not found ``` -------------------------------- ### Paginate Query Results with ResponseExtensions Source: https://context7.com/commercetools/commercetools-dotnet-core-sdk-v2/llms.txt Use ResponseExtensions for pagination utilities like calculating page index, total pages, and detecting first/last pages. Ensure WithTotal(true) is used for total counts. ```csharp using commercetools.Sdk.Api.Extensions; var page = await projectRoot.Products() .Get() .WithLimit(20) .WithOffset(40) .WithWithTotal(true) .ExecuteAsync(); // These extension methods are accessible via reflection or direct extension call // Head: first result (useful for slug queries) var first = page.Results.FirstOrDefault(); // Pagination metadata long pageIndex = (long)Math.Floor(page.Offset / (decimal)page.Limit); // 2 (zero-based) long totalPages = (long)Math.Ceiling((page.Total ?? 0) / (decimal)page.Limit); bool isFirstPage = page.Offset == 0; bool isLastPage = page.Offset + page.Count >= page.Total; Console.WriteLine($"Page {pageIndex + 1} of {totalPages}"); Console.WriteLine($"Showing {page.Count} of {page.Total} products"); ``` -------------------------------- ### Configure Commercetools API Services Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/README.md Register the Commercetools API client with the dependency injection container. Ensure your IConfiguration provides the necessary client settings. ```csharp services.UseCommercetoolsApi(this.configuration, "Client"); // replace with your instance of IConfiguration ``` ```csharp services.UseCommercetoolsImportApi(this.configuration, "ImportClient"); ``` ```csharp services.UseCommercetoolsHistoryApi(this.configuration, "HistoryClient"); ``` -------------------------------- ### Custom Middleware with DelegatingMiddleware Source: https://context7.com/commercetools/commercetools-dotnet-core-sdk-v2/llms.txt Explains how to create and register custom middleware by extending `DelegatingMiddleware` to add custom logic to the HTTP request pipeline. ```APIDOC ## Custom middleware — `DelegatingMiddleware` Custom middleware can be injected into the client's HTTP pipeline to add cross-cutting behaviour such as request tracing, retry logic, or header injection. Extend `DelegatingMiddleware`, override `SendAsync`, and pass instances via `ClientOptions` or `ClientBuilder.Middlewares`. ```csharp public class RequestIdMiddleware : DelegatingMiddleware { protected internal override async Task SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { request.Headers.TryAddWithoutValidation("X-Request-Id", Guid.NewGuid().ToString()); return await base.SendAsync(request, cancellationToken); } } // Register via DI services.UseCommercetoolsApi( configuration, "Client", middlewares: new[] { new RequestIdMiddleware() }); // Or via ClientBuilder var client = new ClientBuilder { ClientName = "Client", ClientConfiguration = config, TokenProvider = tokenProvider, SerializerService = serializerService, HttpClient = httpFactory.CreateClient("Client"), Middlewares = new[] { new RequestIdMiddleware() } }.Build(); ``` ``` -------------------------------- ### Query Categories: V2 vs V1 SDK in C# Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/docs/COMPARISON.md Shows how to query categories with a 'where' clause. V2 uses '.Categories().Get().WithWhere()', while V1 uses '.Builder().Categories().Query().Where()'. Note the different syntax for string comparisons. ```csharp var response = await projectApiRoot .Categories() .Get() .WithWhere($"key = \"{category.Key}\"") .ExecuteAsync(); ``` ```csharp var response = await client .Builder() .Categories() .Query() .Where(c => c.Key == category.Key.valueOf()) .ExecuteAsync(); ``` -------------------------------- ### Type-Safe GraphQL Queries with ZeroQL Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/docs/GraphQL.md This snippet illustrates using the enhanced GraphQL client provided by the SDK, which integrates with ZeroQL for type-safe query building. It shows how to define variables and construct a typed query with a selector for specific fields. ```APIDOC ## Type-Safe GraphQL Queries with ZeroQL ### Description This example demonstrates using the `GraphQLClient` for type-safe GraphQL queries. It leverages ZeroQL to build queries and projections, ensuring that the results are mapped to strongly-typed C# objects. This approach enhances developer experience and reduces runtime errors. ### Method POST ### Endpoint `/graphql` (Implied by `_projectApiRoot.GraphQLClient()`) ### Parameters #### Request Body (Implicitly constructed by `client.Query`) - **variables** (object) - An anonymous object or other type containing variables for the query. - **selector** (static delegate) - A delegate defining the query structure and the fields to be projected. ### Request Example ```csharp var client = _projectApiRoot.GraphQLClient(); var variables = new { productFilter = $"id = \"{productId}\"" }; var response = await client.Query(variables, static (i, o) => o.Products(where: i.productFilter, selector: r => new { results = r.Results(product => new { product.Id }) })); ``` ### Response #### Success Response (200) - **data** (GraphQLDataResponse) - A strongly-typed response object containing the queried data. - **errors** (List) - A list of errors, if any occurred during query execution. #### Response Example ```csharp Assert.Null(response.Errors); Assert.NotNull(response.Data?.results[0].Id); ``` ``` -------------------------------- ### Create Category Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/docs/COMPARISON.md Compares the V2 and V1 SDK methods for creating a category. ```APIDOC ## Create Category ### Description Creates a new category using the Composable Commerce API. ### V2 SDK Example ```csharp var categoryDraft = new CategoryDraft { Name = new LocalizedString {{"en", "Name"}}, Slug = new LocalizedString {{"en", "Slug"}}, Key = "Key" }; var category = await projectApiRoot .Categories() .Post(categoryDraft) .ExecuteAsync(); ``` ### V1 SDK Example ```csharp var categoryDraft = new CategoryDraft { Name = new LocalizedString {{"en", "Name"}}, Slug = new LocalizedString {{"en", "Slug"}}, Key = "Key" }; var category = await client .Builder() .Categories() .Create(categoryDraft) .ExecuteAsync(); ``` ``` -------------------------------- ### Execute Raw GraphQL Queries in C# Source: https://context7.com/commercetools/commercetools-dotnet-core-sdk-v2/llms.txt Send raw GraphQL queries to the commercetools endpoint using the Graphql() method. The response is an IGraphQLResponse, with data accessible as a JsonElement. ```csharp var response = await projectRoot.Graphql() .Post(new GraphQLRequest { Query = @"query($productFilter: String) { products(where: $productFilter) { results { id name(locale: "en") } } }", Variables = new GraphQLVariablesMap { { "productFilter", $"id = \"{productId}\"" } } }) .ExecuteAsync(); // Navigate the JSON element tree var id = ((JsonElement)response.Data) .GetProperty("products") .GetProperty("results")[0] .GetProperty("id") .GetString(); Console.WriteLine(id); // "product-uuid" ``` -------------------------------- ### Category Operations Source: https://github.com/commercetools/commercetools-dotnet-core-sdk-v2/blob/master/README.md Demonstrates how to perform various operations on categories using the SDK, including creation, retrieval by ID and key, querying, updating, and deletion. ```APIDOC ## Create Category ### Description Creates a new category. ### Method POST ### Endpoint /categories ### Request Body - **Name** (LocalizedString) - Required - The name of the category. - **Slug** (LocalizedString) - Required - The slug of the category. - **Key** (string) - Required - The unique key of the category. ### Request Example ```json { "Name": {"en": "Name"}, "Slug": {"en": "Slug"}, "Key": "Key" } ``` ### Response #### Success Response (201 Created) - **Category** (Category) - The created category object. #### Response Example ```json { "id": "some-category-id", "version": 1, "name": {"en": "Name"}, "slug": {"en": "Slug"}, "key": "Key" } ``` ## Get Category by ID ### Description Retrieves a category by its unique ID. ### Method GET ### Endpoint /categories/{id} ### Parameters #### Path Parameters - **id** (string) - Required - The ID of the category to retrieve. ### Response #### Success Response (200 OK) - **Category** (Category) - The requested category object. #### Response Example ```json { "id": "some-category-id", "version": 1, "name": {"en": "Name"}, "slug": {"en": "Slug"}, "key": "Key" } ``` ## Get Category by Key ### Description Retrieves a category by its unique key. ### Method GET ### Endpoint /categories/key={key} ### Parameters #### Query Parameters - **key** (string) - Required - The key of the category to retrieve. ### Response #### Success Response (200 OK) - **Category** (Category) - The requested category object. #### Response Example ```json { "id": "some-category-id", "version": 1, "name": {"en": "Name"}, "slug": {"en": "Slug"}, "key": "Key" } ``` ## Query Categories ### Description Queries categories based on specified criteria. ### Method GET ### Endpoint /categories ### Parameters #### Query Parameters - **where** (string) - Optional - Criteria to filter categories (e.g., `key = "some-key"`). ### Response #### Success Response (200 OK) - **response** (CategoryQueryResponse) - A response object containing a list of categories. #### Response Example ```json { "results": [ { "id": "some-category-id", "version": 1, "name": {"en": "Name"}, "slug": {"en": "Slug"}, "key": "Key" } ], "total": 1 } ``` ## Delete Category by ID ### Description Deletes a category by its unique ID. ### Method DELETE ### Endpoint /categories/{id} ### Parameters #### Path Parameters - **id** (string) - Required - The ID of the category to delete. #### Query Parameters - **version** (long) - Required - The current version of the category. ### Response #### Success Response (200 OK) - **Category** (Category) - The deleted category object. #### Response Example ```json { "id": "some-category-id", "version": 2, "name": {"en": "Name"}, "slug": {"en": "Slug"}, "key": "Key" } ``` ## Update Category ### Description Updates an existing category. ### Method POST ### Endpoint /categories/{id} ### Parameters #### Path Parameters - **id** (string) - Required - The ID of the category to update. ### Request Body - **Version** (long) - Required - The current version of the category. - **Actions** (List) - Required - A list of update actions to perform. - **CategoryChangeNameAction** - **Name** (LocalizedString) - Required - The new name for the category. ### Request Example ```json { "Version": 1, "Actions": [ { "action": "changeName", "Name": {"en": "newName"} } ] } ``` ### Response #### Success Response (200 OK) - **Category** (Category) - The updated category object. #### Response Example ```json { "id": "some-category-id", "version": 2, "name": {"en": "newName"}, "slug": {"en": "Slug"}, "key": "Key" } ``` ## Delete Category by Key ### Description Deletes a category by its unique key. ### Method DELETE ### Endpoint /categories/key={key} ### Parameters #### Query Parameters - **key** (string) - Required - The key of the category to delete. - **version** (long) - Required - The current version of the category. ### Response #### Success Response (200 OK) - **Category** (Category) - The deleted category object. #### Response Example ```json { "id": "some-category-id", "version": 2, "name": {"en": "Name"}, "slug": {"en": "Slug"}, "key": "Key" } ``` ```