2017-05-30 213 views
0

我在不同的網站發現了這個代碼或類似的代碼,在我的應用程序中,沒有引發錯誤,但下載了PDF文件,打開文件時已損壞,其只有5KB下載pdf文件與.NET Core損壞

文件的網址是:

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); 

     } 
+0

你能嘗試沒有指定'HttpCompletionOption.ResponseHeadersRead'?對我來說,它只會下載標題並忽略響應主體。 – juunas

+1

等待Task.FromResult(不管)什麼都可以替換。它已經過時了 –

回答

1

你應該考慮廣告ecoupled設計,這將使您的應用程序更易於維護和測試。

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)) 
    {} 
}