[英]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
看起來像控制器的const
或static string
屬性)
public class MyController
{
public MyController() : this(
new StreamLoader( @"\\pc030\TemporaryPDF\" ),
new AzureStreamRepository( StorageAccount, UploaderStorage.Container ) )
{}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.