如何在不使用他们的SDK的情况下使用.NET HttpClient上传到AmazonS3



如何仅使用.NET的HttpClient(或WebClient)将文件上传到AmazonS3上的bucket?必须使用"PUT"来完成。

我可以使用亚马逊的AWS SDK上传,但我想知道没有它怎么做。我看了他们的文档好几个小时了,仍然没有得到。

如有任何帮助,我们将不胜感激。

我使用他们SDK的代码是:

public static void TestPutObjectAsync() {
AmazonS3Client client = new AmazonS3Client();
client.AfterResponseEvent += new ResponseEventHandler(callback);
PutObjectRequest request = new PutObjectRequest {
BucketName = BUCKET_NAME,
Key = "Item1",
FilePath = FILE_PATH,
};
client.PutObjectAsync(request);
}
public static event EventHandler UploadComplete;
public static void callback(object sender, ResponseEventArgs e) {
if (UploadComplete != null) {
UploadComplete(sender, e);
}
}

我在Xamarin.net核心跨平台客户端中部署文件上传时遇到了这个问题,在该客户端中,预先签署的帖子是使用boto3在服务器端生成的。

要求是不要使用SDK客户端,因为虽然这个问题是关于AWS S3的,许多其他服务(例如Wasabi&Digital Ocean)使用相同的API,并且针对不同服务的SDK客户端的配置可能太难管理了——服务器应该处理为各种服务端点生成预签名POST的问题,而客户端不必镜像该端点。这样,我们的服务器可以很容易地更改端点,而客户端不需要更新。

1:为预先签署的帖子创建支持模型。这源于https://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3.html#generating-预先签署的职位

public class PresignedPost
{
public string url { get; set; }
public Fields fields { get; set; }
}
public class Fields
{
public string AWSAccessKeyId { get; set; }
public string acl { get; set; }
public string key { get; set; }
public string policy { get; set; }
public string signature { get; set; }
}

2:加载文件。在我们的案例中,我们通过读取内存

string data = File.ReadAllText(filepath)

是的,这可能会导致内存中的大文件出现问题,但目前我们的需求中没有解决这一限制。

3:使用System.Net.Http 中的HttpClient创建Upload方法

public static async Task<bool> Upload(PresignedPost presignedPost, string data)
{            
using (HttpClient client = new HttpClient())
{
try
{
MultipartFormDataContent formData = new MultipartFormDataContent
{
{ new StringContent(presignedPost.fields.acl), "acl" },
{ new StringContent(presignedPost.fields.AWSAccessKeyId), "AWSAccessKeyId" },
{ new StringContent(presignedPost.fields.key), "key" },
{ new StringContent(presignedPost.fields.policy), "policy" },
{ new StringContent(presignedPost.fields.signature), "signature" },
{ new StringContent(data), "file" },
};
var response = await client.PostAsync(presignedPost.url, formData);
//if response is 204 no content it's successful
if (response.StatusCode == HttpStatusCode.NoContent)
{
return true;
}
}
catch (Exception ex)
{
//do something with exception
}
}
return false;
}

评论:

1:也可以将文件加载为字节数组,然后使用formData中的内存流。当上传较大的文件时,这可能会有所帮助。然而,我们的堆栈首先对文件进行加密并返回一个字符串,所以我们在这个实现中没有选择该方法。ref:C#HttpClient 4.5多部分/表单数据上传或者简单地使用字节数组而不是字符串ref:在商店应用中通过HTTPPOST发送字节数组

2:您可能会注意到,我们假设204响应代码意味着成功上传。虽然这显然是危险的,但我们找不到任何关于为什么会发生这种情况的文档——也许这与AWS S3 Object DELETE也返回204的原因相同。如果您担心这一点,您可以使用API调用来检查该文件是否存在。

3:是的,使用"using"来处理HttpClients存在争议,您可以根据您的用例参考进行选择:https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

4:是否返回bool,再次请根据您自己的实践和要求进行选择。

最后,我希望这能帮助任何面临这个问题的人,因为AWS S3文档中没有现成的例子。

不知道你为什么不想使用SDK(这就是它的作用),但即使你不想使用整个AWSSDK,你仍然可以使用它的一部分,或者至少可以看看他们是如何在幕后完成的。

这里都是开源的:

https://github.com/aws/aws-sdk-net/tree/master/AWSSDK_DotNet45/Amazon.S3

最终,你要寻找的答案就在那里——但这可能比拔出它的价值更大。

最新更新