This page shows a complete C# example for authenticating and sending a request to the OpenSearch API, including signing, retry logic, and response handling.
Prerequisites
Before you begin, make sure you have:
An Alibaba Cloud account with OpenSearch enabled
An AccessKey pair for a Resource Access Management (RAM) user with the
AliyunServiceRoleForOpenSearchrole granted. See Create a RAM user and Access authorization rules
Use a RAM user's AccessKey pair rather than your Alibaba Cloud account's AccessKey pair. An account-level AccessKey pair grants access to all API operations and poses a higher security risk if leaked. Never include credentials directly in your code.
Set environment variables
Set the following environment variables with your RAM user's AccessKey ID and secret.
Linux and macOS
export ALIBABA_CLOUD_ACCESS_KEY_ID=<access_key_id> export ALIBABA_CLOUD_ACCESS_KEY_SECRET=<access_key_secret>Windows
Create an environment variable file and add the
ALIBABA_CLOUD_ACCESS_KEY_IDandALIBABA_CLOUD_ACCESS_KEY_SECRETvariables, set to your AccessKey ID and secret.Restart Windows for the changes to take effect.
Install dependencies
Install the following NuGet packages. Use the exact versions listed — these four packages must be version-compatible with each other.
dotnet add package AlibabaCloud.TeaUtil --version 0.1.5
dotnet add package AlibabaCloud.OpenSearchUtil --version 1.0.2
dotnet add package Aliyun.Credentials --version 1.2.1
dotnet add package Tea --version 0.4.0Download packages from https://www.nuget.org/packages.
If you use incompatible package versions, the following error occurs at runtime. Install the exact versions listed above to resolve it.
System.MissingMethodException: Method not found: 'System.String Tea.Utils.Extensions.Get(System.Collections.Generic.Dictionary`2<System.String,System.String>, System.String, System.String)'.
at AlibabaCloud.OpenSearchUtil.Common.GetSignature(TeaRequest request, String accessKeySecret)
at AlibabaCloud.OpenSearchUtil.Common.GetSignature(TeaRequest request, String accessKeyId, String accessKeySecret)Sample code
The following example builds and sends a signed HTTP request to the OpenSearch API. The Client class handles credential loading, header construction, request signing, and retry on failure.
// This file is auto-generated, don't edit it. Thanks.
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Tea;
using Tea.Utils;
public class Client
{
protected string _endpoint;
protected string _protocol;
protected string _userAgent;
protected Aliyun.Credentials.Client _credential;
public Client(Config config)
{
if (AlibabaCloud.TeaUtil.Common.IsUnset(config.ToMap()))
{
throw new TeaException(new Dictionary<string, string>
{
{"name", "ParameterMissing"},
{"message", "'config' can not be unset"},
});
}
if (AlibabaCloud.TeaUtil.Common.Empty(config.Type))
{
config.Type = "access_key";
}
Aliyun.Credentials.Models.Config credentialConfig = new Aliyun.Credentials.Models.Config
{
AccessKeyId = config.AccessKeyId,
Type = config.Type,
AccessKeySecret = config.AccessKeySecret,
SecurityToken = config.SecurityToken,
};
this._credential = new Aliyun.Credentials.Client(credentialConfig);
this._endpoint = config.Endpoint;
this._protocol = config.Protocol;
this._userAgent = config.UserAgent;
}
public Dictionary<string, object> _request(string method, string pathname, Dictionary<string, object> query,
Dictionary<string, string> headers, object body, AlibabaCloud.TeaUtil.Models.RuntimeOptions runtime)
{
Dictionary<string, object> runtime_ = new Dictionary<string, object>
{
{"timeouted", "retry"},
{"readTimeout", runtime.ReadTimeout},
{"connectTimeout", runtime.ConnectTimeout},
{"httpProxy", runtime.HttpProxy},
{"httpsProxy", runtime.HttpsProxy},
{"noProxy", runtime.NoProxy},
{"maxIdleConns", runtime.MaxIdleConns},
{"retry", new Dictionary<string, object>
{
{"retryable", runtime.Autoretry},
{"maxAttempts", AlibabaCloud.TeaUtil.Common.DefaultNumber(runtime.MaxAttempts, 1)},
}
},
{"backoff", new Dictionary<string, object>
{
{"policy", AlibabaCloud.TeaUtil.Common.DefaultString(runtime.BackoffPolicy, "no")},
{"period", AlibabaCloud.TeaUtil.Common.DefaultNumber(runtime.BackoffPeriod, 1)},
}
},
{"ignoreSSL", runtime.IgnoreSSL},
};
TeaRequest _lastRequest = null;
Exception _lastException = null;
long _now = System.DateTime.Now.Millisecond;
int _retryTimes = 0;
while (TeaCore.AllowRetry((IDictionary) runtime_["retry"], _retryTimes, _now))
{
if (_retryTimes > 0)
{
int backoffTime = TeaCore.GetBackoffTime((IDictionary) runtime_["backoff"], _retryTimes);
if (backoffTime > 0)
{
TeaCore.Sleep(backoffTime);
}
}
_retryTimes = _retryTimes + 1;
try
{
TeaRequest request_ = new TeaRequest();
// Load credentials from environment variables set earlier.
string accesskeyId = System.Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_ID");
string accessKeySecret = System.Environment.GetEnvironmentVariable("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
string securityToken = this._credential.GetSecurityToken();
request_.Protocol = AlibabaCloud.TeaUtil.Common.DefaultString(_protocol, "HTTP");
request_.Method = method;
request_.Pathname = pathname;
// Build required headers: Date, host, and a nonce for replay protection.
request_.Headers = TeaConverter.merge<string>
(
new Dictionary<string, string>()
{
{"user-agent", AlibabaCloud.TeaUtil.Common.GetUserAgent(this._userAgent )},
{"Date", AlibabaCloud.OpenSearchUtil.Common.GetDate()},
{"host", AlibabaCloud.TeaUtil.Common.DefaultString(_endpoint, "opensearch-cn-hangzhou.aliyuncs.com")},
{"X-Opensearch-Nonce", AlibabaCloud.TeaUtil.Common.GetNonce()},
},
headers
);
if (!AlibabaCloud.TeaUtil.Common.IsUnset(query))
{
request_.Query = AlibabaCloud.TeaUtil.Common.StringifyMapValue(query);
}
if (!AlibabaCloud.TeaUtil.Common.IsUnset(body))
{
// Serialize the request body to JSON and add Content-MD5 for integrity verification.
string reqBody = AlibabaCloud.TeaUtil.Common.ToJSONString(body);
request_.Headers["Content-MD5"] = AlibabaCloud.OpenSearchUtil.Common.GetContentMD5(reqBody);
request_.Headers["Content-Type"] = "application/json";
request_.Body = TeaCore.BytesReadable(reqBody);
}
if (!AlibabaCloud.TeaUtil.Common.IsUnset(securityToken))
{
// Include the security token when using STS temporary credentials.
request_.Headers["X-Opensearch-Security-Token"] = securityToken;
}
// Sign the request using the AccessKey ID and secret.
request_.Headers["Authorization"] =
AlibabaCloud.OpenSearchUtil.Common.GetSignature(request_, accesskeyId, accessKeySecret);
_lastRequest = request_;
TeaResponse response_ = TeaCore.DoAction(request_, runtime_);
// Parse the response body as JSON.
string objStr = AlibabaCloud.TeaUtil.Common.ReadAsString(response_.Body);
object obj = AlibabaCloud.TeaUtil.Common.ParseJSON(objStr);
Console.WriteLine(objStr);
Dictionary<string, object> res = AlibabaCloud.TeaUtil.Common.AssertAsMap(obj);
// Throw on 4xx or 5xx status codes.
if (AlibabaCloud.TeaUtil.Common.Is4xx(response_.StatusCode) ||
AlibabaCloud.TeaUtil.Common.Is5xx(response_.StatusCode))
{
throw new TeaException(new Dictionary<string, object>
{
{"message", response_.StatusMessage},
{"data", res},
{"code", response_.StatusCode},
});
}
return new Dictionary<string, object>
{
{"body", res},
{"headers", response_.Headers}
};
}
catch (Exception e)
{
if (TeaCore.IsRetryable(e))
{
_lastException = e;
continue;
}
throw;
}
}
throw new TeaUnretryableException(_lastRequest, _lastException);
}
}How the code works
The _request method follows this sequence for every API call:
Load credentials — reads
ALIBABA_CLOUD_ACCESS_KEY_IDandALIBABA_CLOUD_ACCESS_KEY_SECRETfrom environment variables. If the config includes a security token (for STS temporary credentials), it is retrieved viaGetSecurityToken().Build headers — sets the required HTTP headers:
Date,host(defaults toopensearch-cn-hangzhou.aliyuncs.com), andX-Opensearch-Nonce(a one-time value that prevents replay attacks).Serialize the request body — if the request has a body, it is serialized to JSON. A
Content-MD5header is added for integrity verification, andContent-Typeis set toapplication/json.Sign the request — the
Authorizationheader is computed from the request using the AccessKey ID and secret. This is required for every API call.Send and retry — the request is sent via
TeaCore.DoAction. If it fails with a retryable error, the loop retries up toMaxAttemptstimes (default: 1) with the configured backoff policy (default: none). On retry exhaustion,TeaUnretryableExceptionis thrown.Handle the response — the response body is parsed as JSON. Status codes in the 4xx or 5xx range throw a
TeaExceptionwith the status code, message, and response data.
| Setting | Default value |
|---|---|
Endpoint (host header) | opensearch-cn-hangzhou.aliyuncs.com |
| Protocol | HTTP |
| Credential type | access_key |
| Max retry attempts | 1 |
| Backoff policy | no |