Form upload allows web applications to upload files directly to OSS using standard HTML forms. This topic describes how to use the C# SDK V2 to generate information, such as Post signatures and Post Policies, and call the HTTP POST method to upload files to OSS.
Precautions
The sample code in this topic uses the China (Hangzhou) region ID,
cn-hangzhou, as an example. By default, the public endpoint is used. If you want to access OSS from other Alibaba Cloud products in the same region, use the internal endpoint. For more information about OSS regions and endpoints, see OSS regions and endpoints.The size of an object uploaded using form upload cannot exceed 5 GB.
Sample code
The following sample code shows the complete form upload process. The main steps are as follows:
Initialize configurations and parameters: Set the region, bucket, object key, and product. Load the access credential from environment variables and prepare the content to upload.
Create a Post Policy: Define the validity period and conditions for the upload request.
Serialize and encode the Policy: Serialize the Policy into a JSON string and perform Base64 encoding.
Generate a signature key: Use the HMAC-SHA256 algorithm to generate an initial key based on the AccessKeySecret. Then, sequentially hash the date, region, product, and request type to generate the final signature key.
Construct the request body: Create multipart form data that complies with the HTTP POST specification. Add the object key, Base64-encoded Policy, signature version, credential information, request date, signature, and the data to upload.
Create and execute the request: Create an HTTP client and send a POST request to the OSS endpoint. Process the response and output the status code and response header information.
using OSS = AlibabaCloud.OSS.V2; // Create an alias for Alibaba Cloud OSS SDK to simplify subsequent use.
using System.Globalization;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
var region = "cn-hangzhou"; // Required. Set the region where the bucket is located. This topic uses China (Hangzhou) as an example. Set the region to cn-hangzhou.
var bucket = "your bucket name"; // Required. The name of the bucket.
var key = "your object key"; // Required. The name of the destination object to upload.
var product = "oss"; // Required. The product identifier for OSS.
// Convert a byte array to a hexadecimal string.
static string ToHexString(byte[] data, bool lowercase)
{
var sb = new StringBuilder();
for (var i = 0; i < data.Length; i++) sb.Append(data[i].ToString(lowercase ? "x2" : "X2"));
return sb.ToString();
}
// Add double quotation marks to a string.
static string quote(string value)
{
return $"\"{value}\"";
}
// Load the default configurations of the OSS SDK. This configuration automatically reads credential information (such as AccessKey) from environment variables.
var cfg = OSS.Configuration.LoadDefault();
// Explicitly set to use environment variables to obtain credentials for identity verification (format: OSS_ACCESS_KEY_ID, OSS_ACCESS_KEY_SECRET).
var credentialsProvider = new OSS.Credentials.EnvironmentVariableCredentialsProvider();
var credentials = credentialsProvider.GetCredentials();
// The content to upload.
var content = "hello oss";
// Construct the Policy (upload policy).
var utcTime = DateTime.UtcNow;
var date = utcTime.ToUniversalTime().ToString("yyyyMMdd", CultureInfo.InvariantCulture);
var dateTime = utcTime.ToUniversalTime().ToString("yyyyMMdd'T'HHmmss'Z'", CultureInfo.InvariantCulture);
var expiration = utcTime.AddHours(1); // The signature is valid for 1 hour.
// Construct credential information.
var credentialInfo = $"{credentials.AccessKeyId}/{date}/{region}/{product}/aliyun_v4_request";
// Construct the Policy JSON.
var policyMap = new Dictionary<string, Object>()
{
// Set the expiration time of the policy.
{ "expiration",
expiration.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss.000'Z'", CultureInfo.InvariantCulture)
},
// Set the upload conditions.
{ "conditions", new Object[]{
// The object must be uploaded to the specified bucket.
new Dictionary<string, string>() {{ "bucket", bucket } },
// Specify the signature version.
new Dictionary<string, string>() {{ "x-oss-signature-version", "OSS4-HMAC-SHA256" } },
// Specify the credential information.
new Dictionary<string, string>() {{ "x-oss-credential", credentialInfo } },
// Specify the request time.
new Dictionary<string, string>() {{ "x-oss-date", dateTime } },
// Limit the range of the upload content length.
new Object[]{"content-length-range", 1, 1024 },
//new Object[]{"eq", "$success_action_status", "201"},
//new Object[]{"starts-with", "$key", "user/eric/"},
//new Object[]{"in", "$content-type", new string[]{"image/jpg", "image/png"}},
//new Object[]{ "not-in", "$cache-control", new string[]{ "no-cache" } },
}
},
};
// Serialize to a JSON string.
var policy = JsonSerializer.Serialize(policyMap);
// Perform Base64 encoding on the Policy.
var stringToSign = Convert.ToBase64String(Encoding.UTF8.GetBytes(policy));
// Generate the signature key.
using var kha = new HMACSHA256();
// The initial key is generated from the AccessKeySecret.
var ksecret = Encoding.UTF8.GetBytes("aliyun_v4" + credentials.AccessKeySecret);
// Generate the signature key level by level.
kha.Key = ksecret;
var hashDate = kha.ComputeHash(Encoding.UTF8.GetBytes(date));
kha.Key = hashDate;
var hashRegion = kha.ComputeHash(Encoding.UTF8.GetBytes(region));
kha.Key = hashRegion;
var hashProduct = kha.ComputeHash(Encoding.UTF8.GetBytes(product));
kha.Key = hashProduct;
var signingKey = kha.ComputeHash(Encoding.UTF8.GetBytes("aliyun_v4_request"));
// Calculate the final signature.
kha.Key = signingKey;
var signature = ToHexString(kha.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)), true);
// Construct the multipart form data.
using var formData = new MultipartFormDataContent();
// Handle the quotation mark issue for the boundary.
var boundary = formData.Headers.ContentType!.Parameters.ElementAt(0).Value!;
formData.Headers.ContentType.Parameters.ElementAt(0).Value = boundary.Trim('"');
// Add a form field - the object key name.
formData.Add(new ByteArrayContent(Encoding.UTF8.GetBytes(key)), quote("key"));
// You can add metadata.
//formData.Add(new ByteArrayContent(Encoding.UTF8.GetBytes(value)), quote("x-oss-"));
// Add the Policy.
formData.Add(new ByteArrayContent(Encoding.UTF8.GetBytes(stringToSign)), quote("policy"));
// Add signature-related information.
formData.Add(new ByteArrayContent(Encoding.UTF8.GetBytes("OSS4-HMAC-SHA256")), quote("x-oss-signature-version"));
formData.Add(new ByteArrayContent(Encoding.UTF8.GetBytes(credentialInfo)), quote("x-oss-credential"));
formData.Add(new ByteArrayContent(Encoding.UTF8.GetBytes(dateTime)), quote("x-oss-date"));
formData.Add(new ByteArrayContent(Encoding.UTF8.GetBytes(signature)), quote("x-oss-signature"));
// Add the content to be uploaded.
formData.Add(new ByteArrayContent(Encoding.UTF8.GetBytes(content)), quote("file"));
// Send a POST request to OSS.
using var hc = new HttpClient();
var result = await hc.PostAsync($"http://{bucket}.oss-{region}.aliyuncs.com/", formData);
// Print the upload result.
Console.WriteLine("PostObject done"); // Indicates that the operation is complete.
Console.WriteLine($"StatusCode: {result.StatusCode}"); // HTTP status code.
Console.WriteLine("Response Headers:"); // Response header information.
result.Headers.ToList().ForEach(x => Console.WriteLine(x.Key + " : " + String.Join(",", x.Value.ToList()))); // Traverse and print all response headers.References
For the complete sample code for form upload, see postObject.cs.