2017-05-30 214 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)) 
    {} 
}