Luis Valencia
Luis Valencia

Reputation: 33988

PDF File is corrupted when dowloaded via c#

I have a REST API which must get a file from a remote URL in AWS servers. The file is downloaded but when I try to open it, it shows nothing, like corrupted.

No exceptions are thrown

the code is this

[HttpPost]
        [Route("api/[controller]/UploadFileToAzureStorage")]
        public async Task<IActionResult> GetFile([FromBody]PDF urlPdf)
        {
            string localFilePath = CreateTemporaryFile(urlPdf.urlPDF);

            // Create storage account
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(StorageAccount);

            // Create a blob client.
            CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

            // Get a reference to a container named "mycontainer."
            CloudBlobContainer container = blobClient.GetContainerReference(UploaderStorage.Container);

            // Get a reference to a blob named "myblob".
            CloudBlockBlob blockBlob = container.GetBlockBlobReference("myblob");

            // Create or overwrite the "myblob" blob with the contents of a local file
            // named "myfile".
            using (var fileStream = System.IO.File.OpenRead(localFilePath))
            {
                await blockBlob.UploadFromStreamAsync(fileStream);
            }

            return Ok();
        }


        /// <summary>
        /// Creates temporary file
        /// </summary>
        /// <param name="urlPdf">PDF URL</param>
        /// <returns>Returns path of the new file</returns>
        private string CreateTemporaryFile(string urlPdf)
        {
            Uri uri = new Uri(urlPdf);
            string filename = default(string);
            //if (uri.IsFile)
            //{
                filename = System.IO.Path.GetFileName(uri.LocalPath);
            //}

            try
            {
                using (var client = new HttpClient())
                {
                    using (HttpResponseMessage response =
                        client.GetAsync(urlPdf, HttpCompletionOption.ResponseHeadersRead).Result)
                    {
                        response.EnsureSuccessStatusCode();

                        using (Stream contentStream = response.Content.ReadAsStreamAsync().Result, fileStream = new FileStream(@"\\pc030\TemporaryPDF\"+ filename,
                            FileMode.Create, FileAccess.Write, FileShare.None, 8192, true))
                        {
                            var buffer = new byte[8192];
                            var isMoreToRead = true;
                            do
                            {
                                var read = contentStream.ReadAsync(buffer, 0, buffer.Length).Result;
                                if (read == 0)
                                {
                                    isMoreToRead = false;
                                }
                                else
                                {
                                    fileStream.WriteAsync(buffer, 0, read);
                                }
                            }

                            while (isMoreToRead);
                        }
                    }
                }

                return @"\\pc030\TemporaryPDF\" + filename;
            }
            catch(Exception ex)
            {
                throw ex;
            }
        }

Upvotes: 0

Views: 1414

Answers (1)

spender
spender

Reputation: 120400

response.Content.ReadAsStreamAsync().Result and contentStream.ReadAsync(buffer, 0, buffer.Length).Result are a deadlock-bomb waiting to go off in your code.

Never block by waiting on Task.Result in UI code or server code unless you fully understand the implications of doing so.

Both server and UI use a special SynchronizationContext that schedules the async continuation back to the calling thread. When that same thread is already hung, waiting for Result, everything can lock-up.

Read and digest:

https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

Your CreateTemporaryFile method should be marked async and you should be awaiting those calls.

So, to your problem. You're calling fileStream.WriteAsync(buffer, 0, read) without awaiting the Task's completion. On the (at least) last write, the stream will be disposed before the write is complete, with predicable results.

Adopt async properly or don't use it at all. There's no half-way house.

Upvotes: 9

Related Questions