1- using System ;
1+ using System ;
22using System . Collections . Generic ;
33using System . IO ;
44using System . Linq ;
@@ -21,8 +21,8 @@ public class AzureFileStorage : IFileStorage, IHaveLogger, IHaveLoggerFactory, I
2121 private readonly BlobContainerClient _container ;
2222 private readonly ISerializer _serializer ;
2323 private readonly ILoggerFactory _loggerFactory ;
24- protected readonly ILogger _logger ;
25- protected readonly TimeProvider _timeProvider ;
24+ private readonly ILogger _logger ;
25+ private readonly TimeProvider _timeProvider ;
2626
2727 public AzureFileStorage ( AzureFileStorageOptions options )
2828 {
@@ -45,7 +45,9 @@ public AzureFileStorage(AzureFileStorageOptions options)
4545 }
4646
4747 public AzureFileStorage ( Builder < AzureFileStorageOptionsBuilder , AzureFileStorageOptions > config )
48- : this ( config ( new AzureFileStorageOptionsBuilder ( ) ) . Build ( ) ) { }
48+ : this ( config ( new AzureFileStorageOptionsBuilder ( ) ) . Build ( ) )
49+ {
50+ }
4951
5052 ISerializer IHaveSerializer . Serializer => _serializer ;
5153 ILogger IHaveLogger . Logger => _logger ;
@@ -75,15 +77,15 @@ public async Task<Stream> GetFileStreamAsync(string path, StreamMode streamMode,
7577 _ => throw new NotSupportedException ( $ "Stream mode { streamMode } is not supported.")
7678 } ;
7779 }
78- catch ( RequestFailedException ex ) when ( ex . Status == 404 )
80+ catch ( RequestFailedException ex ) when ( ex . Status is 404 )
7981 {
8082 _logger . LogDebug ( ex , "[{Status}] Unable to get file stream for {Path}: File Not Found" , ex . Status , normalizedPath ) ;
8183 return null ;
8284 }
8385 catch ( RequestFailedException ex )
8486 {
8587 _logger . LogError ( ex , "[{Status}] Unable to get file stream for {Path}: {Message}" , ex . Status , normalizedPath , ex . Message ) ;
86- throw ;
88+ throw new StorageException ( "Unable to get file stream." , ex ) ;
8789 }
8890 }
8991
@@ -100,7 +102,7 @@ public async Task<FileSpec> GetFileInfoAsync(string path)
100102 var properties = await blobClient . GetPropertiesAsync ( ) . AnyContext ( ) ;
101103 return ToFileInfo ( normalizedPath , properties . Value ) ;
102104 }
103- catch ( RequestFailedException ex ) when ( ex . Status == 404 )
105+ catch ( RequestFailedException ex ) when ( ex . Status is 404 )
104106 {
105107 _logger . LogDebug ( ex , "[{Status}] Unable to get file info for {Path}: File Not Found" , ex . Status , normalizedPath ) ;
106108 return null ;
@@ -205,21 +207,22 @@ public async Task<bool> CopyFileAsync(string path, string targetPath, Cancellati
205207 var targetBlob = _container . GetBlobClient ( normalizedTargetPath ) ;
206208
207209 var copyOperation = await targetBlob . StartCopyFromUriAsync ( sourceBlob . Uri , cancellationToken : cancellationToken ) . AnyContext ( ) ;
208- // TODO: Instead of true should we be checking copyOperation.HasCompleted? and copyOperation.UpdateStatusAsync
209- // Wait for copy to complete
210- while ( true )
210+
211+ // Wait for copy operation to complete
212+ await copyOperation . WaitForCompletionAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
213+ if ( ! copyOperation . HasCompleted )
211214 {
212- var properties = await targetBlob . GetPropertiesAsync ( cancellationToken : cancellationToken ) . AnyContext ( ) ;
213- if ( properties . Value . CopyStatus == CopyStatus . Success )
214- return true ;
215- if ( properties . Value . CopyStatus == CopyStatus . Failed || properties . Value . CopyStatus == CopyStatus . Aborted )
216- {
217- _logger . LogError ( "Copy operation failed for {Path} to {TargetPath}: {CopyStatus}" , normalizedPath , normalizedTargetPath , properties . Value . CopyStatus ) ;
218- return false ;
219- }
220-
221- await _timeProvider . Delay ( TimeSpan . FromMilliseconds ( 50 ) , cancellationToken ) . AnyContext ( ) ;
215+ _logger . LogError ( "Copy operation did not complete for {Path} to {TargetPath}" , normalizedPath , normalizedTargetPath ) ;
216+ return false ;
222217 }
218+
219+ // Check final status
220+ var properties = await targetBlob . GetPropertiesAsync ( cancellationToken : cancellationToken ) . AnyContext ( ) ;
221+ if ( properties . Value . CopyStatus == CopyStatus . Success )
222+ return true ;
223+
224+ _logger . LogError ( "Copy operation failed for {Path} to {TargetPath}: {CopyStatus}" , normalizedPath , normalizedTargetPath , properties . Value . CopyStatus ) ;
225+ return false ;
223226 }
224227 catch ( RequestFailedException ex )
225228 {
@@ -341,24 +344,22 @@ private async Task<List<FileSpec>> GetFileListAsync(string searchPattern = null,
341344
342345 private static FileSpec ToFileInfo ( BlobItem blob )
343346 {
344- // TODO: We used to check if Properties.Length was -1 in old storage extension and return null. I'm not sure why this was ever needed. But if we do we need to be sure we filter nulls out.
345347 return new FileSpec
346348 {
347349 Path = blob . Name ,
348350 Size = blob . Properties . ContentLength ?? - 1 ,
349- Created = blob . Properties . LastModified ? . UtcDateTime ?? DateTime . MinValue ,
351+ Created = blob . Properties . CreatedOn ? . UtcDateTime ?? DateTime . MinValue ,
350352 Modified = blob . Properties . LastModified ? . UtcDateTime ?? DateTime . MinValue
351353 } ;
352354 }
353355
354356 private static FileSpec ToFileInfo ( string path , BlobProperties properties )
355357 {
356- // TODO: We used to check if Properties.Length was -1 in old storage extension and return null. I'm not sure why this was ever needed. But if we do we need to be sure we filter nulls out.
357358 return new FileSpec
358359 {
359360 Path = path ,
360361 Size = properties . ContentLength ,
361- Created = properties . LastModified . UtcDateTime ,
362+ Created = properties . CreatedOn . UtcDateTime ,
362363 Modified = properties . LastModified . UtcDateTime
363364 } ;
364365 }
0 commit comments