All Products
Search
Document Center

Object Storage Service:Configure object tagging

Last Updated:Oct 18, 2023

Object Storage Service (OSS) allows you to configure object tags to classify objects. You can configure lifecycle rules and control access to objects based on tags.

Note

For more information about object tags, see Object tagging.

Usage notes

  • In this topic, the public endpoint of the China (Hangzhou) region is used. If you want to access OSS by using other Alibaba Cloud services in the same region as OSS, use an internal endpoint. For more information about the regions and endpoints supported by OSS, see Regions and endpoints.

  • In this topic, an OSSClient instance is created by using an OSS endpoint. If you want to create an OSSClient instance by using custom domain names or Security Token Service (STS), see Initialization.

  • To add a tag to an object, you must have the oss:PutObjectTagging permission. For more information, see Attach a custom policy to a RAM user.

Add tags to an object when you upload the object

The following examples describe how to add tags to an object in simple upload, multipart upload, append upload, and resumable upload:

  • Add tags to an object when you upload the object by using simple upload

    The following code provides an example on how to add tags to an object when you upload it by using simple upload:

    using System.Text;
    using Aliyun.OSS;
    using System.Text;
    using Aliyun.OSS.Util;
    
    // Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. 
    var endpoint = "yourEndpoint";
    // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. 
    var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
    var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
    // Specify the name of the bucket. 
    var bucketName = "examplebucket";
    // Specify the full path of the object. Do not include the bucket name in the full path. 
    var objectName = "exampleobject.txt";
    var objectContent = "More than just cloud.";
    
    String UrlEncodeKey(String key)
    {
    const string CharsetName = "utf-8";
    const char separator = '/';
    var segments = key.Split(separator);
    
    var encodedKey = new StringBuilder();
    encodedKey.Append(HttpUtils.EncodeUri(segments[0], CharsetName));
    for (var i = 1; i < segments.Length; i++)
        encodedKey.Append(separator).Append(HttpUtils.EncodeUri(segments[i], CharsetName));
    
        if (key.EndsWith(separator.ToString()))
        {
            // String#split ignores trailing empty strings, e.g., "a/b/" will be split as a 2-entries array,
            // so we have to append all the trailing slash to the uri.
            foreach (var ch in key)
            {
                if (ch == separator)
                    encodedKey.Append(separator);
                else
                    break;
            }
        }
    
    return encodedKey.ToString();
    }
    // Create an OSSClient instance. 
    var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
    try
    {
        byte[] binaryData = Encoding.ASCII.GetBytes(objectContent);
        MemoryStream requestContent = new MemoryStream(binaryData);
    
        var meta = new ObjectMetadata();
        // Configure the tags in the HTTP headers. 
        string str = UrlEncodeKey("key1") + "=" + UrlEncodeKey("value1") + "&" + UrlEncodeKey("key2") + "=" + UrlEncodeKey("value2");
        meta.AddHeader("x-oss-tagging", str);
        var putRequest = new PutObjectRequest(bucketName, objectName, requestContent);
        putRequest.Metadata = meta;
    
        // Upload the object and add tags to the object. 
        client.PutObject(putRequest);
        Console.WriteLine("Put object succeeded");
    }
    catch (Exception ex)
    {
        Console.WriteLine("Put object failed, {0}", ex.Message);
    }
  • Add tags to an object when you upload the object by using multipart upload

    The following code provides an example on how to add tags to an object when you upload it by using multipart upload:

    using Aliyun.OSS;
    using Aliyun.OSS.Util;
    using System.Text;
    
    // Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. 
    var endpoint = "yourEndpoint";
    // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. 
    var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
    var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
    // Specify the name of the bucket. 
    var bucketName = "examplebucket";
    // Specify the full path of the object. Do not include the bucket name in the full path. 
    var objectName = "exampleobject.txt";
    // Specify the full path of the local file. Example: D:\\localpath\\examplefile.txt. By default, if you do not specify the full path of the local file, the local file is uploaded from the path of the project to which the sample program belongs. 
    var localFilename = "D:\\localpath\\examplefile.txt";
    
    String UrlEncodeKey(String key)
    {
    const string CharsetName = "utf-8";
    const char separator = '/';
    var segments = key.Split(separator);
    
    var encodedKey = new StringBuilder();
    encodedKey.Append(HttpUtils.EncodeUri(segments[0], CharsetName));
    for (var i = 1; i < segments.Length; i++)
        encodedKey.Append(separator).Append(HttpUtils.EncodeUri(segments[i], CharsetName));
    
        if (key.EndsWith(separator.ToString()))
        {
            // String#split ignores trailing empty strings, e.g., "a/b/" will be split as a 2-entries array,
            // so we have to append all the trailing slash to the uri.
            foreach (var ch in key)
            {
                if (ch == separator)
                    encodedKey.Append(separator);
                else
                    break;
            }
        }
    
    return encodedKey.ToString();
    }
    
    // Create an OSSClient instance. 
    var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
    // Initiate the multipart upload task. 
    var uploadId = "";
    try
    {
        // Specify the name of the object and the bucket to which the object is uploaded. You can configure object metadata in InitiateMultipartUploadRequest. However, you do not need to specify ContentLength. 
        var request = new InitiateMultipartUploadRequest(bucketName, objectName);
    
        var meta = new ObjectMetadata();
        // Configure the tags in the HTTP headers. 
        string str = UrlEncodeKey("key1") + "=" + UrlEncodeKey("value1") + "&" + UrlEncodeKey("key2") + "=" + UrlEncodeKey("value2");
        meta.AddHeader("x-oss-tagging", str);
        request.ObjectMetadata = meta;
    
        var result = client.InitiateMultipartUpload(request);
        uploadId = result.UploadId;
        // Display the upload ID. 
        Console.WriteLine("Init multi part upload succeeded");
        Console.WriteLine("Upload Id:{0}", result.UploadId);
    }
    catch (Exception ex)
    {
        Console.WriteLine("Init multi part upload failed, {0}", ex.Message);
    }
    // Calculate the total number of parts. 
    var partSize = 100 * 1024;
    var fi = new FileInfo(localFilename);
    var fileSize = fi.Length;
    var partCount = fileSize / partSize;
    if (fileSize % partSize != 0)
    {
        partCount++;
    }
    // Start the multipart upload task. partETags is a list of part ETags. OSS verifies the validity of each part after it receives the part list. After all parts are verified, OSS combines these parts into a complete object. 
    var partETags = new List<PartETag>();
    try
    {
        using (var fs = File.Open(localFilename, FileMode.Open))
        {
            for (var i = 0; i < partCount; i++)
            {
                var skipBytes = (long)partSize * i;
                // Find the start position of the current upload task. 
                fs.Seek(skipBytes, 0);
                // Calculate the part size of this upload. The size of the last part is the size of the remainder after the object is split by the calculated part size. 
                var size = (partSize < fileSize - skipBytes) ? partSize : (fileSize - skipBytes);
                var request = new UploadPartRequest(bucketName, objectName, uploadId)
                {
                    InputStream = fs,
                    PartSize = size,
                    PartNumber = i + 1
                };
                // Call UploadPart to upload the parts. The returned results contain the ETag values of the parts. 
                var result = client.UploadPart(request);
                partETags.Add(result.PartETag);
                Console.WriteLine("finish {0}/{1}", partETags.Count, partCount);
            }
            Console.WriteLine("Put multi part upload succeeded");
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine("Put multi part upload failed, {0}", ex.Message);
    }
    // Complete the multipart upload task. 
    try
    {
        var completeMultipartUploadRequest = new CompleteMultipartUploadRequest(bucketName, objectName, uploadId);
        foreach (var partETag in partETags)
        {
            completeMultipartUploadRequest.PartETags.Add(partETag);
        }
        var result = client.CompleteMultipartUpload(completeMultipartUploadRequest);
        Console.WriteLine("complete multi part succeeded");
    }
    catch (Exception ex)
    {
        Console.WriteLine("complete multi part failed, {0}", ex.Message);
    }
  • Add tags to an object when you upload the object by using append upload

    The following code provides an example on how to add tags to an object when you upload it by using append upload:

    using Aliyun.OSS;
    using Aliyun.OSS.Util;
    using System.Text;
    // Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. 
    var endpoint = "yourEndpoint";
    // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. 
    var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
    var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
    // Specify the name of the bucket. 
    var bucketName = "examplebucket";
    // Specify the full path of the object. Do not include the bucket name in the full path. 
    var objectName = "exampleobject.txt";
    // Specify the full path of the local file. Example: D:\\localpath\\examplefile.txt. By default, if you do not specify the full path of the local file, the local file is uploaded from the path of the project to which the sample program belongs. 
    var localFilename = "D:\\localpath\\examplefile.txt";
    
    String UrlEncodeKey(String key)
    {
    const string CharsetName = "utf-8";
    const char separator = '/';
    var segments = key.Split(separator);
    
    var encodedKey = new StringBuilder();
    encodedKey.Append(HttpUtils.EncodeUri(segments[0], CharsetName));
    for (var i = 1; i < segments.Length; i++)
        encodedKey.Append(separator).Append(HttpUtils.EncodeUri(segments[i], CharsetName));
    
        if (key.EndsWith(separator.ToString()))
        {
            // String#split ignores trailing empty strings, e.g., "a/b/" will be split as a 2-entries array,
            // so we have to append all the trailing slash to the uri.
            foreach (var ch in key)
            {
                if (ch == separator)
                    encodedKey.Append(separator);
                else
                    break;
            }
        }
    
    return encodedKey.ToString();
    }
    // Create an OSSClient instance. 
    var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
    // If the object is appended for the first time, the position from which the append operation starts is 0. The start position for the next append operation is included in the response. The position from which the next append upload starts is the current length of the object. 
    long position = 0;
    try
    {
        var metadata = client.GetObjectMetadata(bucketName, objectName);
        position = metadata.ContentLength;
    }
    catch (Exception) { }
    try
    {
        using (var fs = File.Open(localFilename, FileMode.Open))
        {
            var request = new AppendObjectRequest(bucketName, objectName)
            {
                ObjectMetadata = new ObjectMetadata(),
                Content = fs,
                Position = position
            };
    
            var meta = new ObjectMetadata();
            // Configure the tags in the HTTP headers. 
             string str = UrlEncodeKey("key1") + "=" + UrlEncodeKey("value1") + "&" + UrlEncodeKey("key2") + "=" + UrlEncodeKey("value2");
            meta.AddHeader("x-oss-tagging", str);
            request.ObjectMetadata = meta;
    
            // Perform the first append operation. Only the tags configured when the object is appended for the first time are added to the object. 
            var result = client.AppendObject(request);
            // Specify the position from which the append operation starts. 
            position = result.NextAppendPosition;
            Console.WriteLine("Append object succeeded, next append position:{0}", position);
        }
        // Obtain the position for the next append operation and perform the second append operation. 
        using (var fs = File.Open(localFilename, FileMode.Open))
        {
            var request = new AppendObjectRequest(bucketName, objectName)
            {
                ObjectMetadata = new ObjectMetadata(),
                Content = fs,
                Position = position
            };
            var result = client.AppendObject(request);
            position = result.NextAppendPosition;
            Console.WriteLine("Append object succeeded, next append position:{0}", position);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine("Append object failed, {0}", ex.Message);
    }
  • Add tags to an object when you upload the object by using resumable upload

    The following code provides an example on how to add tags to an object when you upload it by using resumable upload:

    using Aliyun.OSS;
    using Aliyun.OSS.Common;
    using Aliyun.OSS.Util;
    using System.Text;
    // Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. 
    var endpoint = "yourEndpoint";
    // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. 
    var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
    var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
    // Specify the name of the bucket. 
    var bucketName = "examplebucket";
    // Specify the full path of the object. Do not include the bucket name in the full path. 
    var objectName = "exampleobject.txt";
    // Specify the full path of the local file. Example: D:\\localpath\\examplefile.txt. By default, if you do not specify the full path of the local file, the local file is uploaded from the path of the project to which the sample program belongs. 
    var localFilename = "D:\\localpath\\examplefile.txt";
    // Specify the checkpoint file that records the upload result of each part. The checkpoint file stores information about the upload progress. 
    string checkpointDir = "yourCheckpointDir";
    String UrlEncodeKey(String key)
    {
    const string CharsetName = "utf-8";
    const char separator = '/';
    var segments = key.Split(separator);
    
    var encodedKey = new StringBuilder();
    encodedKey.Append(HttpUtils.EncodeUri(segments[0], CharsetName));
    for (var i = 1; i < segments.Length; i++)
        encodedKey.Append(separator).Append(HttpUtils.EncodeUri(segments[i], CharsetName));
    
        if (key.EndsWith(separator.ToString()))
        {
            // String#split ignores trailing empty strings, e.g., "a/b/" will be split as a 2-entries array,
            // so we have to append all the trailing slash to the uri.
            foreach (var ch in key)
            {
                if (ch == separator)
                    encodedKey.Append(separator);
                else
                    break;
            }
        }
    
    return encodedKey.ToString();
    }
    // Create an OSSClient instance. 
    var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
    try
    {
        // Configure parameters by using UploadFileRequest. 
        UploadObjectRequest request = new UploadObjectRequest(bucketName, objectName, localFilename)
        {
            // Specify the size of each part. 
            PartSize = 8 * 1024 * 1024,
            // Specify the number of concurrent threads. 
            ParallelThreadCount = 3,
            // checkpointDir is used to record the result of multipart upload. This file stores information about upload progress. If a part fails to be uploaded, the task can be continued based on the progress recorded in the file. If you set checkpointDir to null, resumable upload does not take effect and the object is re-uploaded if the object fails to be uploaded. 
            CheckpointDir = checkpointDir,
        };
    
        var meta = new ObjectMetadata();
        // Configure the tags in the HTTP headers. 
        string str = UrlEncodeKey("key1") + "=" + UrlEncodeKey("value1") + "&" + UrlEncodeKey("key2") + "=" + UrlEncodeKey("value2");
        meta.AddHeader("x-oss-tagging", str);
        request.Metadata = meta;
    
        // Start resumable upload. 
        client.ResumableUploadObject(request);
        Console.WriteLine("Resumable upload object:{0} succeeded", objectName);
    }
    catch (OssException ex)
    {
        Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
            ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
    }
    catch (Exception ex)
    {
        Console.WriteLine("Failed with error info: {0}", ex.Message);
    }

Add tags to an uploaded object or modify the tags of the object

The following code provides an example on how to add tags to an uploaded object or modify the tags of the object:

using Aliyun.OSS;
// Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. 
var endpoint = "yourEndpoint";
// Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. 
var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
// Specify the name of the bucket. 
var bucketName = "examplebucket";
// Specify the full path of the object. Do not include the bucket name in the full path. 
var objectName = "exampleobject.txt";

// Create an OSSClient instance. 
var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
try
{
    // Configure the tags that you want to add to the object. 
    var setRequest = new SetObjectTaggingRequest(bucketName, objectName);

    var tag1 = new Tag
    {
        Key = "project",
        Value = "projectone"
    };

    var tag2 = new Tag
    {
        Key = "user",
        Value = "jsmith"
    };

    setRequest.AddTag(tag1);
    setRequest.AddTag(tag2);
    client.SetObjectTagging(setRequest);
    Console.WriteLine("set object tagging succeeded");
}
catch (Exception ex)
{
    Console.WriteLine("set object tagging failed. {0}", ex.Message);
}

Add tags to an object when you copy the object

You can use the one of following methods to configure object tagging when you copy an object:

  • Copy: The tag of the source object is copied to the destination object.

  • Replace: The destination object has the tag specified in the request instead of the tag of the source object.

The following examples describe how to add tags to an object smaller than 1 GB in simple copy mode and larger than 1 GB in multipart copy mode:

  • The following code provides an example on how to add tags to an object smaller than 1 GB in size when you copy the object by using simple copy:

    using Aliyun.OSS;
    using Aliyun.OSS.Common;
    using Aliyun.OSS.Util;
    using System.Text;
    
    // Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. 
    var endpoint = "yourEndpoint";
    // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. 
    var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
    var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
    // Specify the name of the source bucket. Example: srcexamplebucket. 
    var sourceBucket = "srcexamplebucket";
    // Specify the full path of the source object. Do not include the bucket name in the full path. Example: srcdir/scrobject.txt. 
    var sourceObject = "srcdir/scrobject.txt";
    // Specify the name of the destination bucket. The destination bucket must be in the same region as the source bucket. Example: destbucket. 
    var targetBucket = "destbucket";
    // Specify the full path of the destination object. Do not include the bucket name in the full path. Example: destdir/destobject.txt. 
    var targetObject = "destdir/destobject.txt";
    
    String UrlEncodeKey(String key)
    {
    const string CharsetName = "utf-8";
    const char separator = '/';
    var segments = key.Split(separator);
    
    var encodedKey = new StringBuilder();
    encodedKey.Append(HttpUtils.EncodeUri(segments[0], CharsetName));
    for (var i = 1; i < segments.Length; i++)
        encodedKey.Append(separator).Append(HttpUtils.EncodeUri(segments[i], CharsetName));
    
        if (key.EndsWith(separator.ToString()))
        {
            // String#split ignores trailing empty strings, e.g., "a/b/" will be split as a 2-entries array,
            // so we have to append all the trailing slash to the uri.
            foreach (var ch in key)
            {
                if (ch == separator)
                    encodedKey.Append(separator);
                else
                    break;
            }
        }
    
    return encodedKey.ToString();
    }
    // Create an OSSClient instance. 
    var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
    try
    {
        var metadata = new ObjectMetadata();
        metadata.AddHeader("mk1", "mv1");
        metadata.AddHeader("mk2", "mv2");
    
        // Configure the tags in the HTTP headers. 
        string str = UrlEncodeKey("key1") + "=" + UrlEncodeKey("value1") + "&" + UrlEncodeKey("key2") + "=" + UrlEncodeKey("value2");
        metadata.AddHeader("x-oss-tagging", str);
    
        var req = new CopyObjectRequest(sourceBucket, sourceObject, targetBucket, targetObject)
        {
            // If the value of NewObjectMetadata is null, the Copy mode is used to copy the metadata of the source object. Otherwise, the Replace mode is used to overwrite the metadata of the source object. 
            NewObjectMetadata = metadata 
        };
        // Copy the object. 
        client.CopyObject(req);
        Console.WriteLine("Copy object succeeded");
    }
    catch (OssException ex)
    {
        Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID: {2} \tHostID: {3}",
            ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
    }
    catch (Exception ex)
    {
        Console.WriteLine("Failed with error info: {0}", ex.Message);
    }
  • The following code provides an example on how to add tags to an object larger than 1 GB in size when you copy the object by using multipart copy:

    using Aliyun.OSS;
    using Aliyun.OSS.Common;
    using Aliyun.OSS.Util;
    using System.Text;
    
    // Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. 
    var endpoint = "yourEndpoint";
    // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. 
    var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
    var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
    // Specify the name of the source bucket. Example: srcexamplebucket. 
    var sourceBucket = "srcexamplebucket";
    // Specify the full path of the source object. Do not include the bucket name in the full path. Example: srcdir/scrobject.txt. 
    var sourceObject = "srcdir/scrobject.txt";
    // Specify the name of the destination bucket. The destination bucket must be in the same region as the source bucket. Example: destbucket. 
    var targetBucket = "destbucket";
    // Specify the full path of the destination object. Do not include the bucket name in the full path. Example: destdir/destobject.txt. 
    var targetObject = "destdir/destobject.txt";
    var uploadId = "";
    var partSize = 50 * 1024 * 1024;
    String UrlEncodeKey(String key)
    {
    const string CharsetName = "utf-8";
    const char separator = '/';
    var segments = key.Split(separator);
    
    var encodedKey = new StringBuilder();
    encodedKey.Append(HttpUtils.EncodeUri(segments[0], CharsetName));
    for (var i = 1; i < segments.Length; i++)
        encodedKey.Append(separator).Append(HttpUtils.EncodeUri(segments[i], CharsetName));
    
        if (key.EndsWith(separator.ToString()))
        {
            // String#split ignores trailing empty strings, e.g., "a/b/" will be split as a 2-entries array,
            // so we have to append all the trailing slash to the uri.
            foreach (var ch in key)
            {
                if (ch == separator)
                    encodedKey.Append(separator);
                else
                    break;
            }
        }
    
    return encodedKey.ToString();
    }
    // Create an OSSClient instance. 
    var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
    try
    {
        // Initiate a multipart copy task. You can call the InitiateMultipartUploadRequest operation to specify the metadata of the destination object. 
        var request = new InitiateMultipartUploadRequest(targetBucket, targetObject);
        var meta = new ObjectMetadata();
        // Configure the tags in the HTTP headers. 
        string str = UrlEncodeKey("key1") + "=" + UrlEncodeKey("value1") + "&" + UrlEncodeKey("key2") + "=" + UrlEncodeKey("value2");
        meta.AddHeader("x-oss-tagging", str);
        request.ObjectMetadata = meta;
    
        var result = client.InitiateMultipartUpload(request);
        // Display the upload ID. 
        uploadId = result.UploadId;
        Console.WriteLine("Init multipart upload succeeded, Upload Id: {0}", result.UploadId);
        // Calculate the total number of parts. 
        var metadata = client.GetObjectMetadata(sourceBucket, sourceObject);
        var fileSize = metadata.ContentLength;
        var partCount = (int)fileSize / partSize;
        if (fileSize % partSize != 0)
        {
            partCount++;
        }
        // Start the multipart copy task. 
        var partETags = new List<PartETag>();
        for (var i = 0; i < partCount; i++)
        {
            var skipBytes = (long)partSize * i;
            var size = (partSize < fileSize - skipBytes) ? partSize : (fileSize - skipBytes);
            // Create an UploadPartCopyRequest object. You can use UploadPartCopyRequest to specify conditions. 
            var uploadPartCopyRequest = new UploadPartCopyRequest(targetBucket, targetObject, sourceBucket, sourceObject, uploadId)
                {
                    PartSize = size,
                    PartNumber = i + 1,
                    // Use BeginIndex to find the start position to copy the part. 
                    BeginIndex = skipBytes
                };
            // Call the UploadPartCopy method to copy each part. 
            var uploadPartCopyResult = client.UploadPartCopy(uploadPartCopyRequest);
            Console.WriteLine("UploadPartCopy : {0}", i);
            partETags.Add(uploadPartCopyResult.PartETag);
        }
        // Complete the multipart copy task. 
        var completeMultipartUploadRequest =
        new CompleteMultipartUploadRequest(targetBucket, targetObject, uploadId);
        // partETags is a list of partETags. OSS verifies the validity of each part after it receives partETags. After all parts are verified, OSS combines these parts into a complete object. 
        foreach (var partETag in partETags)
        {
            completeMultipartUploadRequest.PartETags.Add(partETag);
        }
        var completeMultipartUploadResult = client.CompleteMultipartUpload(completeMultipartUploadRequest);
        Console.WriteLine("CompleteMultipartUpload succeeded");
    }
    catch (OssException ex)
    {
        Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID: {2} \tHostID: {3}",
            ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
    }
    catch (Exception ex)
    {
        Console.WriteLine("Failed with error info: {0}", ex.Message);
    }

Add tags to a symbolic link

The following code provides an example on how to add tags to a symbolic link:

using Aliyun.OSS;
using Aliyun.OSS.Util;
using System.Text;
// Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. 
var endpoint = "yourEndpoint";
// Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. 
var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
// Specify the name of the bucket. 
var bucketName = "examplebucket";
// Specify the full path of the object. Do not include the bucket name in the full path. 
var targetObjectName = "exampleobject.txt";
// Specify the name of the symbolic link. Example: symlink.txt. 
var symlinkObjectName = "symlink.txt";
var objectContent = "More than just cloud.";
String UrlEncodeKey(String key)
{
const string CharsetName = "utf-8";
const char separator = '/';
var segments = key.Split(separator);

var encodedKey = new StringBuilder();
encodedKey.Append(HttpUtils.EncodeUri(segments[0], CharsetName));
for (var i = 1; i < segments.Length; i++)
    encodedKey.Append(separator).Append(HttpUtils.EncodeUri(segments[i], CharsetName));

    if (key.EndsWith(separator.ToString()))
    {
        // String#split ignores trailing empty strings, e.g., "a/b/" will be split as a 2-entries array,
        // so we have to append all the trailing slash to the uri.
        foreach (var ch in key)
        {
            if (ch == separator)
                encodedKey.Append(separator);
            else
                break;
        }
    }

return encodedKey.ToString();
}
// Create an OSSClient instance. 
var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
try
{
    // Upload the object. 
    byte[] binaryData = Encoding.ASCII.GetBytes(objectContent);
    MemoryStream requestContent = new MemoryStream(binaryData);
    client.PutObject(bucketName, targetObjectName, requestContent);

    var meta = new ObjectMetadata();
    // Configure the tags in the HTTP headers. 
    string str = UrlEncodeKey("key1") + "=" + UrlEncodeKey("value1") + "&" + UrlEncodeKey("key2") + "=" + UrlEncodeKey("value2");
    meta.AddHeader("x-oss-tagging", str);
    var request = new CreateSymlinkRequest(bucketName, symlinkObjectName, targetObjectName);
    request.ObjectMetadata = meta;
    // Create the symbolic link. 
    client.CreateSymlink(request);
    // Obtain the name of the object to which you want the symbolic link to point. 
    var ossSymlink = client.GetSymlink(bucketName, symlinkObjectName);
    Console.WriteLine("Target object is {0}", ossSymlink.Target);
}
catch (Exception ex)
{
    Console.WriteLine("Failed with error info: {0}", ex.Message);
}

References

For more information about the API operation that you can call to configure object tagging, see PutObjectTagging.