// Copyright © 2022 Dmitry Sikorsky. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using ExtCore.FileStorage.Abstractions;
namespace ExtCore.FileStorage.Azure;
///
/// Implements the IDirectoryProxy interface and represents a file in a Azure Storage account.
///
public class FileProxy : IFileProxy
{
private readonly string connectionString;
private readonly string filepath;
private readonly string containerName;
private readonly string blobName;
///
/// The path of the underlying file relatively to the root one.
///
public string RelativePath { get; private set; }
///
/// The filename of the underlying file.
///
public string Filename { get; private set; }
///
/// Initializes a new instance of the FileProxy class.
///
/// The Azure Storage account connection string.
/// The root path of the underlying file's relative one.
/// The path of the underlying file relatively to the root one.
/// The filename of the underlying file.
///
///
public FileProxy(string connectionString, string rootPath, string relativePath, string filename)
{
if (connectionString == string.Empty)
throw new ArgumentException($"Value can't be empty. Parameter name: connectionString.");
if (connectionString == null)
throw new ArgumentNullException($"Value can't be null. Parameter name: connectionString.", default(Exception));
if (filename == string.Empty)
throw new ArgumentException($"Value can't be empty. Parameter name: filename.");
if (filename == null)
throw new ArgumentNullException($"Value can't be null. Parameter name: filename.", default(Exception));
this.connectionString = connectionString;
this.RelativePath = RelativeUrl.Combine(relativePath);
this.Filename = filename;
this.filepath = RelativeUrl.Combine(rootPath, this.RelativePath, this.Filename);
string[] urlSegments = filepath.Split('/');
this.containerName = urlSegments.First();
this.blobName = string.Join("/", urlSegments.Skip(1));
}
///
/// Checks if the underlying file exists.
///
/// Returns a flag indicating if the underlying file exists.
public async Task ExistsAsync()
{
try
{
BlobClient blobClient = await this.GetBlobClient();
return await blobClient.ExistsAsync();
}
catch
{
return false;
}
}
///
/// Reads content of the underlying file as a byte array.
///
/// Content of the underlying file as a byte array.
///
///
///
///
///
public async Task ReadStreamAsync()
{
try
{
BlobClient blobClient = await this.GetBlobClient();
MemoryStream stream = new MemoryStream();
await blobClient.DownloadToAsync(stream);
stream.Position = 0;
return stream;
}
catch (Exception e)
{
throw new FileStorageException($"Generic file storage exception: \"{this.filepath}\". See inner exception for details.", e);
}
}
///
/// Reads content of the underlying file as a byte array.
///
/// Content of the underlying file as a byte array.
///
///
///
///
///
public async Task ReadBytesAsync()
{
try
{
BlobClient blobClient = await this.GetBlobClient();
BlobDownloadResult downloadResult = await blobClient.DownloadContentAsync();
return downloadResult.Content.ToArray();
}
catch (Exception e)
{
throw new FileStorageException($"Generic file storage exception: \"{this.filepath}\". See inner exception for details.", e);
}
}
///
/// Reads content of the underlying file as a text string.
///
/// Content of the underlying file as a text string.
///
///
///
///
///
public async Task ReadTextAsync()
{
try
{
BlobClient blobClient = await this.GetBlobClient();
BlobDownloadResult downloadResult = await blobClient.DownloadContentAsync();
return downloadResult.Content.ToString();
}
catch (Exception e)
{
throw new FileStorageException($"Generic file storage exception: \"{this.filepath}\". See inner exception for details.", e);
}
}
///
/// Writes content to the underlying file as a stream.
///
/// Content to write to the underlying file as a stream.
///
///
///
///
///
public async Task WriteStreamAsync(Stream inputStream)
{
try
{
BlobClient blobClient = await this.GetBlobClient();
await blobClient.UploadAsync(inputStream);
}
catch (Exception e)
{
throw new FileStorageException($"Generic file storage exception: \"{this.filepath}\". See inner exception for details.", e);
}
}
///
/// Writes content to the underlying file as a byte array.
///
/// Content to write to the underlying file as a byte array.
///
///
///
///
///
public async Task WriteBytesAsync(byte[] bytes)
{
try
{
BlobClient blobClient = await this.GetBlobClient();
await blobClient.UploadAsync(BinaryData.FromBytes(bytes));
}
catch (Exception e)
{
throw new FileStorageException($"Generic file storage exception: \"{this.filepath}\". See inner exception for details.", e);
}
}
///
/// Writes content to the underlying file as a text string.
///
/// Content to write to the underlying file as a text string.
///
///
///
///
///
public async Task WriteTextAsync(string text)
{
try
{
BlobClient blobClient = await this.GetBlobClient();
await blobClient.UploadAsync(BinaryData.FromString(text));
}
catch (Exception e)
{
throw new FileStorageException($"Generic file storage exception: \"{this.filepath}\". See inner exception for details.", e);
}
}
///
/// Deletes the underlying file.
///
///
///
///
///
///
public async Task DeleteAsync()
{
try
{
BlobClient blobClient = await this.GetBlobClient();
await blobClient.DeleteAsync();
}
catch (Exception e)
{
throw new FileStorageException($"Generic file storage exception: \"{this.filepath}\". See inner exception for details.", e);
}
}
private async Task GetBlobClient()
{
BlobServiceClient blobServiceClient = new BlobServiceClient(this.connectionString);
BlobContainerClient blobContainerClient = blobServiceClient.GetBlobContainerClient(this.containerName);
await blobContainerClient.CreateIfNotExistsAsync();
return blobContainerClient.GetBlobClient(this.blobName);
}
}