Demo code for building a request

Updated at:

Set up a C# client for the OpenSearch Industry Algorithm Edition API: install the required NuGet packages, configure credentials from environment variables, and build a signed HTTP request.

Prerequisites

Before you begin, ensure that you have:

  • A .NET project with the dotnet CLI available

  • An Alibaba Cloud account with OpenSearch enabled

  • An AccessKey pair for a Resource Access Management (RAM) user that has the required OpenSearch permissions

Important

Use a RAM user's AccessKey pair instead of your Alibaba Cloud root account credentials. Root account credentials grant full access to all API operations. For setup instructions, see Create a RAM user and Create an AccessKey pair. For the permissions required by the RAM user, see AliyunServiceRoleForOpenSearch and Access authorization rules.

Set environment variables

Store your AccessKey pair as environment variables to keep credentials out of your source code.

  • Linux and macOS — run the following commands, replacing the placeholders with your RAM user's AccessKey ID and AccessKey secret:

    export ALIBABA_CLOUD_ACCESS_KEY_ID=<access_key_id>
    export ALIBABA_CLOUD_ACCESS_KEY_SECRET=<access_key_secret>
  • Windows — create an environment variable file, add ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET, set each to the corresponding value, and restart Windows for the changes to take effect.

Install dependencies

Download and install the following packages from NuGet:

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.0
Use the exact versions listed above. A version mismatch between Tea and AlibabaCloud.OpenSearchUtil causes a runtime exception at the GetSignature call: If you see this error, remove the existing packages and re-add them at the exact versions above.
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)
   at Client._request(String method, String pathname, Dictionary`2 query, Dictionary`2 headers, Object body, RuntimeOptions runtime) in D:\workspace\C#_workspace\MyDoNet\Client.cs:line 131
   at MyDoNet.Program.searchDoc(Client opensearchClient, String appName, Dictionary`2 queryParams, Dictionary`2 header, RuntimeOptions runTime) in D:\workspace\C#_workspace\MyDoNet\Program.cs:line 17
   at MyDoNet.Program.Main(String[] args) in D:\workspace\C#_workspace\MyDoNet\Program.cs:line 84

Sample code

The following Client class builds and signs HTTP requests to the OpenSearch API. It reads credentials from the environment variables you configured, attaches the required headers (Date, X-Opensearch-Nonce, Content-MD5, Authorization), and handles retries with configurable backoff.

// 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();
        // Read AccessKey credentials from environment variables.
        // Set ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET
        // before running this code. See "Set environment variables" above.
        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;
        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))
        {
          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))
        {
          request_.Headers["X-Opensearch-Security-Token"] = securityToken;
        }

        request_.Headers["Authorization"] =
          AlibabaCloud.OpenSearchUtil.Common.GetSignature(request_, accesskeyId, accessKeySecret);
        _lastRequest = request_;
        TeaResponse response_ = TeaCore.DoAction(request_, runtime_);

        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);

        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 it works

  1. The Client constructor initializes credentials and connection settings from the Config object.

  2. _request builds a TeaRequest with the required headers: Date, X-Opensearch-Nonce, Content-MD5 (when a body is present), and Authorization (computed by GetSignature).

  3. If a security token is present, it is attached as X-Opensearch-Security-Token.

  4. The retry loop uses the BackoffPolicy and MaxAttempts settings from RuntimeOptions. The default policy is no backoff with a maximum of one attempt.

  5. HTTP 4xx and 5xx responses throw a TeaException with the status code, status message, and response body.

What's next