Skip to main content
 首页 » 编程设计

c#之使用 ASP.NET Web API 将图像添加到 Azure blob 存储失败

2024年02月27日30wuhuacong

我有一个用于存储图像的 Azure Blob 容器。我还有一套 ASP.NET Web API 方法用于添加/删除/列出此容器中的 blob。如果我将图像作为文件上传,这一切都有效。但我现在想将图像作为流上传,但出现错误。

public async Task<HttpResponseMessage> AddImageStream(Stream filestream, string filename) 
    { 
        try 
        { 
            if (string.IsNullOrEmpty(filename)) 
            { 
                throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.BadRequest)); 
            } 
 
            BlobStorageService service = new BlobStorageService(); 
            await service.UploadFileStream(filestream, filename, "image/png"); 
            var response = Request.CreateResponse(HttpStatusCode.OK); 
            return response; 
        } 
        catch (Exception ex) 
        { 
            base.LogException(ex); 
            throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.BadRequest)); 
        } 

将新图像作为流添加到 blob 容器的代码如下所示。

public async Task UploadFileStream(Stream filestream, string filename, string contentType) 
    { 
        CloudBlockBlob blockBlobImage = this._container.GetBlockBlobReference(filename); 
        blockBlobImage.Properties.ContentType = contentType; 
        blockBlobImage.Metadata.Add("DateCreated", DateTime.UtcNow.ToLongDateString()); 
        blockBlobImage.Metadata.Add("TimeCreated", DateTime.UtcNow.ToLongTimeString()); 
        await blockBlobImage.UploadFromStreamAsync(filestream); 
    } 

最后这是我失败的单元测试。

[TestMethod] 
    public async Task DeployedImageStreamTests() 
    { 
        string blobname = Guid.NewGuid().ToString(); 
 
        //Arrange 
        MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes($"This is a blob called {blobname}.")) 
        { 
            Position = 0 
        }; 
 
        string url = $"http://mywebapi/api/imagesstream?filestream={stream}&filename={blobname}"; 
        Console.WriteLine($"DeployedImagesTests URL {url}"); 
        HttpContent content = new StringContent(blobname, Encoding.UTF8, "application/json"); 
        var response = await ImagesControllerPostDeploymentTests.PostData(url, content); 
 
        //Assert 
        Assert.IsNotNull(response); 
        Assert.IsTrue(response.IsSuccessStatusCode); //fails here!! 
        Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); 
    } 

我收到的错误是值不能为空。 参数名称:source

这是使用 Web API 将图像流上传到 Azure blob 存储的正确方法吗?我可以毫无问题地处理图像文件,现在我正在尝试使用流上传时才遇到这个问题。

请您参考如下方法:

Is this the correct way to upload an image stream to Azure blob storage using Web API? I have it working with image files without a problem, and only getting this problem now that I'm trying to upload using streams.

根据你的描述和报错信息,我发现你将你的url中的流数据发送到web api。

根据这篇文章:

Web API 使用以下规则来绑定(bind)参数:

如果参数是“简单”类型,Web API 会尝试从 URI 中获取值。简单类型包括 .NET 基元类型(int、bool、double 等),加上 TimeSpan、DateTime、Guid、decimal 和 string,以及任何具有可以从字符串转换的类型转换器的类型。 (稍后会详细介绍类型转换器。)

对于复杂类型,Web API 会尝试使用媒体类型格式化程序从消息正文中读取值。

在我看来,流是一种复杂的类型,因此我建议您可以将其作为正文发布到 web api。

此外,我建议您可以创建一个文件类并使用 Newtonsoft.Json 将其转换为 json 作为消息的内容。

更多细节,你可以引用下面的代码。 文件类:

  public class file 
    { 
        //Since JsonConvert.SerializeObject couldn't serialize the stream object I used byte[] instead 
        public byte[] str { get; set; } 
        public string filename { get; set; } 
 
        public string contentType { get; set; } 
    } 

网络接口(interface):

  [Route("api/serious/updtTM")] 
    [HttpPost] 
    public void updtTM([FromBody]file imagefile) 
    { 
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse("aaaaa"); 
            var client = storageAccount.CreateCloudBlobClient(); 
            var container = client.GetContainerReference("images"); 
 
            CloudBlockBlob blockBlobImage = container.GetBlockBlobReference(imagefile.filename); 
            blockBlobImage.Properties.ContentType = imagefile.contentType; 
            blockBlobImage.Metadata.Add("DateCreated", DateTime.UtcNow.ToLongDateString()); 
            blockBlobImage.Metadata.Add("TimeCreated", DateTime.UtcNow.ToLongTimeString()); 
 
            MemoryStream stream = new MemoryStream(imagefile.str) 
            { 
                Position=0 
            }; 
            blockBlobImage.UploadFromStreamAsync(stream); 
        } 

测试控制台:

 using (var client = new HttpClient()) 
            { 
                string URI = string.Format("http://localhost:14456/api/serious/updtTM"); 
                file f1 = new file(); 
 
                byte[] aa = File.ReadAllBytes(@"D:\Capture2.PNG"); 
 
                f1.str = aa; 
                f1.filename = "Capture2"; 
                f1.contentType = "PNG"; 
                var serializedProduct = JsonConvert.SerializeObject(f1);  
                var content = new StringContent(serializedProduct, Encoding.UTF8, "application/json"); 
                var result = client.PostAsync(URI, content).Result; 
            }