Configure Region Endpoints in .NET Utils SDK

View as Markdown
Intermediate12 min read

Overview

Contentstack services are available across multiple regions with different endpoint URLs. Hardcoding these URLs requires code changes as regions and services evolve. The .NET Utils SDK resolves the correct endpoint dynamically from the canonical regions registry, allowing the same initialization code to work across supported regions without hardcoded strings.

Use region resolution when your application supports multiple regions or cloud-specific regions, so you avoid hardcoding endpoint URLs for each one.

Region resolution is optional in these cases, though it still lets you switch regions later without rewriting hardcoded endpoint strings throughout your codebase:

  • Your application only connects to one Contentstack region
  • You hardcode the endpoint

Quick Reference

The following table maps each use case to its section and primary API call.

Use CaseSectionKey Call
Configure the SDK for a regionConfigure the SDK for a RegionEndpoint.GetContentstackEndpoint(region, "contentDelivery", omitHttps: true)
Return all service endpointsReturn All EndpointsEndpoint.GetContentstackEndpoint(region)
Strip https:// for host configurationConfigure the SDK for a RegionEndpoint.GetContentstackEndpoint(..., omitHttps: true)
Read from environment variableRead from Environment VariableEnvironment.GetEnvironmentVariable("CONTENTSTACK_REGION") ?? "na"
Call endpoint resolution via the Contentstack.Utils namespaceUse Utils ProxyUtils.GetContentstackEndpoint(region, "contentDelivery", omitHttps: true)
Look up a valid region ID or aliasSupported RegionsNone
Look up a valid service keySupported Service KeysNone
Diagnose an exception or unexpected resultTroubleshootingNone
Review caching, network behavior, or force a refreshAdvanced: Registry InternalsScripts/refresh-region.py

Prerequisites

Mandatory:

  • contentstack.utils (NuGet page) installed, version 2.0.0-beta.2 or later (the version that introduced Endpoint.GetContentstackEndpoint()). Run dotnet add package contentstack.utils
  • .NET project with dotnet add package support

Optional:

  • Contentstack .NET CDA SDK: .NET CDA SDK Setup Guide (required for the integration examples)
  • Python 3: required only for running Scripts/refresh-region.py to pre-populate the registry in CI/CD pipelines. The SDK downloads the registry automatically on first use and does not require Python at runtime.
  • Familiarity with Contentstack regions: Selecting a Region in SDKs. Your stack's region is set when the stack is created and is visible under Organization Settings → Stacks in the Contentstack dashboard.

Configure the SDK for a Region

On the first call, the SDK loads the region registry and caches the parsed result in memory for the lifetime of the process. Subsequent calls resolve endpoints from the in-memory cache without additional disk or network I/O. See Loading and Caching Priority for the exact priority order and what happens when the on-disk file is stale.

Note: The cache never auto-refreshes. Registry changes on the CDN require a process restart, or a manual Endpoint.ResetCache() call (testing only), to take effect.

Resolve the host and wire it into ContentstackOptions.Host. Most applications should use the default overload, which returns a full HTTPS URL. Use omitHttps: true only when an API specifically expects a hostname without the scheme (such as the Host property), since the SDK adds https:// internally and a full URL would double the scheme. The region argument accepts a region ID or a supported alias, matched case-insensitively. See Region Resolution Rules for the full list of accepted forms.

using Contentstack.Core;
using Contentstack.Core.Configuration;
using Contentstack.Utils.Endpoints;

// Resolve host (no hardcoded string)
string host = Endpoint.GetContentstackEndpoint("<CONTENTSTACK_REGION>", "contentDelivery", omitHttps: true);
// → "eu-cdn.contentstack.com" (for region 'eu')

var stack = new ContentstackClient(new ContentstackOptions
{
    ApiKey        = "<API_KEY>",
    DeliveryToken = "<DELIVERY_TOKEN>",
    Environment   = "<ENVIRONMENT>",
    Host          = host
});

try
{
    var result = await stack
        .ContentType("blog")
        .Query()
        .Find<BlogEntry>();
}
catch (Exception ex)
{
    Console.Error.WriteLine($"Request failed: {ex.Message}");
    throw;
}

To target a different region, change only the region argument.

RegionResolved host
nacdn.contentstack.io
eueu-cdn.contentstack.com
auau-cdn.contentstack.com
azure-naazure-na-cdn.contentstack.com
string host = Endpoint.GetContentstackEndpoint("<CONTENTSTACK_REGION>", "contentDelivery", omitHttps: true);

Return All Endpoints

Use this overload when you need more than one service endpoint for the same region.

Calling Endpoint.GetContentstackEndpoint() without a service argument returns a Dictionary<string, string> with one entry per service key for the region.

using Contentstack.Utils.Endpoints;
using System.Collections.Generic;

Dictionary<string, string> endpoints = Endpoint.GetContentstackEndpoint("<CONTENTSTACK_REGION>");

foreach (var (service, url) in endpoints)
{
    Console.WriteLine($"{service} -> {url}");
}

Read from Environment Variable

using Contentstack.Core;
using Contentstack.Core.Configuration;
using Contentstack.Utils.Endpoints;

string region = Environment.GetEnvironmentVariable("CONTENTSTACK_REGION") ?? "na";

string host = Endpoint.GetContentstackEndpoint(region, "contentDelivery", omitHttps: true);

var stack = new ContentstackClient(new ContentstackOptions
{
    ApiKey        = Environment.GetEnvironmentVariable("CONTENTSTACK_API_KEY"),
    DeliveryToken = Environment.GetEnvironmentVariable("CONTENTSTACK_DELIVERY_TOKEN"),
    Environment   = Environment.GetEnvironmentVariable("CONTENTSTACK_ENVIRONMENT"),
    Host          = host
});

Use Utils Proxy

Utils.GetContentstackEndpoint() is a proxy that produces the same results as Endpoint.GetContentstackEndpoint(). Use it when your codebase already imports Contentstack.Utils and you prefer the shorter call form.

using Contentstack.Utils;

string host = Utils.GetContentstackEndpoint("<CONTENTSTACK_REGION>", "contentDelivery", omitHttps: true);

Endpoint Resolution API

The .NET Utils SDK exposes endpoint resolution via the static Endpoint class in the Contentstack.Utils.Endpoints namespace.

// Returns a single service URL
string Endpoint.GetContentstackEndpoint(
    string region,
    string service,
    bool omitHttps = false)

// Returns all service URLs for a region
Dictionary<string, string> Endpoint.GetContentstackEndpoint(
    string region,
    bool omitHttps = false)

Parameters

ParameterDescription
regionRegion identifier or alias (case-insensitive)
serviceService key (e.g. "contentDelivery")
omitHttpsWhen true, strips the https:// prefix. Required for SDK host configuration.

C# overloads resolve cleanly at compile time, with no ambiguity and no Union types.


Region Resolution Rules

Region matching:

  • Is case-insensitive. The SDK calls ToLowerInvariant() on the input before matching, and does not perform any other normalization.
  • Trims leading/trailing whitespace
  • Supports aliases, matched as literal strings from the regions registry
  • Does not convert between dash (-) and underscore (_) separators. An alias such as aws_na resolves only because the registry lists it as its own literal alias string alongside aws-na, not because the SDK derives one form from the other.
  • ID match takes priority over alias match (two-pass lookup)

For example, aws-na, AWS_NA, and us all resolve to the na region because the registry lists aws-na, aws_na, and us separately as aliases for na. See Supported Regions for the complete list.

Only dash (-) and underscore (_) are recognized as separators. A region string using any other separator (a space, a dot, or a slash, for example "aws na") does not match any known region or alias and falls into the "Invalid region" error below.

If no region is found:

KeyNotFoundException: Invalid region: <input>

Supported Regions

Region IDCloudLocationDefaultAliases
naAWSNorth AmericaYesus, aws-na, aws_na
euAWSEuropeNoaws-eu, aws_eu
auAWSAustraliaNoaws-au, aws_au
azure-naAzureNorth AmericaNoazure_na
azure-euAzureEuropeNoazure_eu
gcp-naGCPNorth AmericaNogcp_na
gcp-euGCPEuropeNogcp_eu

The Regions Registry is the authoritative list of region identifiers and aliases.


Service Resolution Rules

The .NET Utils SDK:

  1. Locates the resolved region
  2. Locates the service key within the region endpoints
  3. Returns the endpoint URL

Example

Region:  eu
Service: contentDelivery
Result:  https://eu-cdn.contentstack.com

If the service is unavailable:

KeyNotFoundException: Service "unknownService" not found for region "eu"

Supported Service Keys

  • contentDelivery
  • contentManagement
  • graphqlDelivery
  • graphqlPreview
  • preview
  • auth
  • application
  • images
  • assets
  • automate
  • launch
  • developerHub
  • brandKit
  • genAI
  • personalizeManagement
  • personalizeEdge
  • composableStudio
  • assetManagement

Note: assetManagement is available for NA only. The Regions Registry is the authoritative list of all region identifiers, aliases, and service endpoint URLs.

This SDK does not expose these values as an enum or typed constants, so copy them exactly.


Troubleshooting

Empty region

Symptom

ArgumentException: Empty region provided. Please put valid region.

Root cause: A null or whitespace-only string was passed as region.

Resolution: Pass a non-empty region string. See Region Resolution Rules for valid identifiers.


Unknown region

Symptom

KeyNotFoundException: Invalid region: <input>

Root cause: The string does not match any region ID or alias in the registry. This is typically caused by a typo or an unsupported region name.

Resolution: Check Supported Regions for valid identifiers and aliases.


Unknown service

Symptom

KeyNotFoundException: Service "<key>" not found for region "<id>"

Root cause: The service key does not exist for the resolved region. Some keys (such as assetManagement) are available for NA only.

Resolution: Verify the service key against Supported Service Keys. For non-NA regions, check region-specific constraints noted in that section.


Null or empty service

Symptom

ArgumentNullException: Value cannot be null. (Parameter 'propertyName')

or, when service is an empty string:

KeyNotFoundException: Service "" not found for region "<id>"

Root cause: Unlike region, the service parameter has no explicit null/empty guard. Passing null propagates into an internal JsonElement.TryGetProperty() call and surfaces as ArgumentNullException. Passing "" is treated as an ordinary (nonexistent) service key and surfaces as the same KeyNotFoundException used for any unknown service.

Resolution: Pass a specific service key from Supported Service Keys, or call the single-argument overload Endpoint.GetContentstackEndpoint(region) to get all endpoints for the region (see Return All Endpoints).


Stale registry after an upstream region or service addition

Symptom

KeyNotFoundException: Invalid region: <input>

or a service that you know Contentstack added still does not appear when you call Endpoint.GetContentstackEndpoint(region), even after you call Endpoint.ResetCache().

Root cause: The local Assets/regions.json file on disk predates the upstream change. Endpoint.ResetCache() only clears the in-memory cache. On the next call, the SDK checks the local Assets/regions.json file on disk first, and only falls back to a live CDN download when that file is missing. If a stale file still exists on disk, ResetCache() alone does not force a network refresh.

Resolution: Run python3 Scripts/refresh-region.py (or python Scripts/refresh-region.py on Windows) to overwrite every bin/**/Assets/regions.json next to the built DLL with the latest registry. See Refreshing the Registry.


Registry unavailable

Symptom

InvalidOperationException: contentstack_utils: regions.json not found and could not be downloaded.

Root cause: The local bin/Assets/regions.json file does not exist and the CDN download also failed. This typically occurs in environments without outbound internet access.

Resolution: Run python3 Scripts/refresh-region.py after restoring network connectivity, or pre-populate bin/Assets/regions.json via your deployment pipeline.


Registry corrupt

Symptom

InvalidOperationException: contentstack_utils: regions.json is corrupt. Run 'python3 Scripts/refresh-region.py' to re-download it.

Root cause: The local regions.json file contains invalid JSON, typically from a truncated download.

Resolution: Run python3 Scripts/refresh-region.py to replace the file with a fresh download.


Write permission denied

Symptom

No exception is thrown. The current process keeps working normally, but regions.json never appears on disk and every new process restart re-downloads it from the CDN.

Root cause: The process running the SDK does not have write access to the bin/Assets/ output directory. The SDK writes the downloaded file inside a try/catch that silently discards write failures, so the failure never surfaces as an exception. This occurs in deployed environments with restricted users, read-only filesystems, or misconfigured CI/CD pipelines.

Resolution: Grant write permission to the output directory, or pre-populate bin/Assets/regions.json via your deployment pipeline before the application starts. Without one of these, each process restart pays the synchronous CDN download cost described in Advanced: Registry Internals.


macOS SSL certificate verification

Symptom

WARNING: SSL certificate verification failed. Retrying without verification.
         To fix permanently, run: /Applications/Python*/Install Certificates.command

Root cause: On macOS with a Python.org build, refresh-region.py may encounter an SSL certificate error on first run. The script retries automatically without verification.

Resolution: Run /Applications/Python*/Install Certificates.command to install the required root certificates permanently.


Advanced: Registry Internals

This section covers registry caching and refresh internals. Skip it unless you are debugging a caching issue or automating registry refresh in a deployment pipeline.

Loading and Caching Priority

The .NET Utils SDK loads the registry in the following priority order, and never commits regions.json to source control (excluded via .gitignore, never packed into the NuGet package):

PrioritySourceBehavior
1In-memory cache (_regionsData)Populated on first call, reused for the lifetime of the process. Zero I/O.
2Local disk file (Assets/regions.json)Read from bin/Assets/ next to Contentstack.Utils.dll in the output directory
3CDN download fallbackDownloads from https://artifacts.contentstack.com/regions.json, writes to disk for future calls

From package install through the first API call, the workflow looks like this:

dotnet add package contentstack.utils
          │
          ▼
dotnet build
  → MSBuild target fires (SDK-style projects using PackageReference only)
  → Scripts/refresh-region.py placed in project
          │
          ▼
dotnet run
  → App starts → first call to GetContentstackEndpoint()
  → regions.json not found on disk
  → Downloads from CDN → writes to bin/Assets/regions.json
  → Cached in memory for process lifetime

Endpoint.ResetCache() clears only priority 1, the in-memory cache. The next call still checks priority 2, the local Assets/regions.json file on disk, first. It reaches priority 3, the CDN, only when that local file is missing. If a stale regions.json file still exists on disk, calling Endpoint.ResetCache() reloads that same stale file and does not reach the CDN. Endpoint.ResetCache() is intended for testing only. Do not call it in production code. See Refreshing the Registry to force a network refresh.

Network Behavior

The CDN download has these characteristics:

  • Timeout: Explicit 30 seconds, via HttpClient.
  • Proxy support: Uses the default HttpClientHandler, which honors the system/environment proxy configuration unless your application explicitly disables it.
  • Firewall: Allow outbound access to artifacts.contentstack.com.

On the first run in a new deployment (no regions.json on disk), the SDK makes a synchronous CDN call before returning the endpoint URL. Run python3 Scripts/refresh-region.py in your deployment pipeline to pre-populate bin/Assets/regions.json and avoid this blocking call in production.

Refreshing the Registry

Scripts/refresh-region.py is bundled inside the NuGet package. On dotnet build, an MSBuild target copies it into your project's Scripts/ folder. This applies to SDK-style projects using PackageReference (the default for .NET Core/5+ projects). It does not run for packages.config-based projects or on dotnet restore alone.

To manually refresh the registry with the latest version from the CDN, run from your project root:

  • For Mac/Linux
python3 Scripts/refresh-region.py
  • For Windows
python Scripts/refresh-region.py
python3 Scripts/refresh-region.py   (run anytime to update)
          │
          ▼
  Download latest regions.json from CDN → overwrite bin/**/Assets/regions.json

This overwrites every bin/**/Assets/regions.json found in your project, making newly added regions and services available without requiring a new SDK release. Run this script whenever a region or service is added upstream after your local regions.json was last refreshed. Endpoint.ResetCache() alone does not force a network download while a local regions.json file still exists on disk, so it does not substitute for running this script.