簡體   English   中英

.NET Core下載的pdf文件已損壞

[英]download pdf file is corrupt with .NET Core

我已在不同的網站中找到此代碼或類似代碼,在我的應用程序中沒有引發任何錯誤,但是下載的PDF文件在打開時已損壞,並且只有5KB

該文件的網址是:

https://optionline-api-files.s3.amazonaws.com/pla592d774e504e8.pdf

我用來下載的代碼是:

[HttpPost]
        [Route("api/[controller]/UploadFileToAzureStorage")]
        public async Task<IActionResult> GetFile([FromBody]PDF urlPdf)
        {
            string localFilePath = await 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 async Task<string> CreateTemporaryFile(string urlPdf)
        {
            Uri uri = new Uri(urlPdf);
            string filename = default(string);

            filename = System.IO.Path.GetFileName(uri.LocalPath);


            using (HttpClient client = new HttpClient())
            {
                using (HttpResponseMessage response = await client.GetAsync(urlPdf, HttpCompletionOption.ResponseHeadersRead))
                using (Stream streamToReadFrom = await response.Content.ReadAsStreamAsync())
                {
                    string fileToWriteTo = @"\\pc030\TemporaryPDF\"+filename;
                    using (Stream streamToWriteTo = System.IO.File.Open(fileToWriteTo, FileMode.Create))
                    {
                        await streamToReadFrom.CopyToAsync(streamToWriteTo);
                    }
                }
            }

            return   await Task.FromResult(@"\\pc030\TemporaryPDF\" + filename);

        }

您應該考慮一種分離的設計,這將使您的應用程序更易於維護和測試。

interface IStreamLoader
{
    Task<Stream> GetStreamAsync( Uri uri );
}

interface IStreamRepository
{
    Task<Stream> GetAsync( string id );
    Task PutAsync( string id, Stream stream );
    Task DeleteAsync( string id );
}

public class MyController
{
    private readonly IStreamLoader _streamLoader;
    private readonly IStreamRepository _streamRepository;

    public MyController( IStreamLoader streamLoader, IStreamRepository streamRepository )
    {
        _streamLoader = streamLoader;
        _streamRepository = streamRepository;
    }

    [Route("api/[controller]/UploadFileToAzureStorage")]
    public async Task<IActionResult> GetFile([FromBody]PDF urlPdf)
    {
        Uri pdfUri = new Uri( urlPDF.urlPDF );
        using ( var pdfStream = await _streamLoader.GetStreamAsync( pdfUri ) )
        {
            await _streamRepository.PutAsync( "myblob", pdfStream );
        }
        return Ok();
    }
}

很干凈,不是嗎? 我們不再關心文件名,因為我們只想擁有一個流。

現在,具有一個不錯的功能的IStreamLoader實現:關閉/處置流時,相關文件將被刪除。 這樣可以使臨時目錄保持干凈。

class StreamLoader : IStreamLoader
{
    private readonly string _tempPath;

    public StreamLoader()
    {

    }

    public StreamLoader( string tempPath )
    {
        _tempPath = tempPath;
    }

    private string GetTempFileName()
    {
        string filename;
        if ( _tempPath == null )
        {
            filename = Path.GetTempFileName();
        }
        else
        {
            filename = Path.Combine( _tempPath, Guid.NewGuid().ToString() );
            using ( File.Create( filename ) )
            { }
        }
        return filename;
    }

    public async Task<Stream> GetStreamAsync( Uri uri )
    {
        Stream result;
        using ( var client = new HttpClient() )
        {
            var response = await client.GetAsync( uri ).ConfigureAwait( false );
            response.EnsureSuccessStatusCode();

            var filename = GetTempFileName();

            using ( var stream = File.OpenWrite( filename ) )
            {
                await response.Content.CopyToAsync( stream );
            }
            result = new FileStream( 
                path: filename, 
                mode: FileMode.Open, 
                access: FileAccess.Read, 
                share: FileShare.None,
                bufferSize: 4096, 
                options: FileOptions.DeleteOnClose );
        }
        return result;
    }
}

最后,我們需要針對Azure的IStreamRepository實現:

class AzureStreamRepository : IStreamRepository
{
    private readonly CloudStorageAccount _storageAccount;
    private readonly string _containerName;

    public AzureStreamRepository( string connectionString, string containerName )
    {
        _storageAccount = CloudStorageAccount.Parse( connectionString );
        _containerName = containerName;
    }

    public async Task DeleteAsync( string id )
    {
        var blockBlob = GetBlockBlob( id );
        await blockBlob.DeleteAsync();
    }

    public async Task<Stream> GetAsync( string id )
    {
        var blockBlob = GetBlockBlob( id );
        Stream result = new MemoryStream();
        try
        {
            await blockBlob.DownloadToStreamAsync( result );
        }
        catch ( Exception )
        {
            result.Dispose();
            throw;
        }
        result.Seek( 0, SeekOrigin.Begin );
        return result;
    }

    public async Task PutAsync( string id, Stream stream )
    {
        var blockBlob = GetBlockBlob( id );
        await blockBlob.UploadFromStreamAsync( stream );
    }

    private Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob GetBlockBlob( string id )
    {
        var client = _storageAccount.CreateCloudBlobClient();
        var container = client.GetContainerReference( _containerName );
        return container.GetBlockBlobReference( id );
    }

}

您應該使用DI將實例注入到控制器中。

對於沒有DI的快速測試,請將此構造函數添加到控制器中( StorageAccount看起來像控制器的conststatic string屬性)

public class MyController
{
    public MyController() : this( 
        new StreamLoader( @"\\pc030\TemporaryPDF\" ),
        new AzureStreamRepository( StorageAccount, UploaderStorage.Container ) )
    {}
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM