我在不同的网站上发现了这段代码或类似的代码,在我的应用程序中,没有抛出任何错误,但下载的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);
}
答案 0 :(得分:1)
您应该考虑一种解耦设计,这将使您的应用程序更易于维护和测试。
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 ) )
{}
}