using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Azure.Storage.Blobs.Specialized;
using gehGassi.Core.Interfaces;
using gehGassi.Core.Services;
namespace gehGassi.External.Services
{
///
/// Service der die Verwaltung von Dateien mittels Azure ermöglicht.
/// Verwendet das neue Azure-Interface
///
public class AzureBlobFileService : IFileService
{
internal BlobServiceClient BlobServiceClient;
///
/// Erstellt eine Instanz
///
/// Connectionstring für Azure-Storage
public AzureBlobFileService(string connectionString)
{
BlobServiceClient = new BlobServiceClient(connectionString);
InitContainers();
}
///
/// Initialisieren der Container
///
/// Task
private void InitContainers()
{
var container = BlobServiceClient.GetBlobContainerClient(FileServiceHelper.DocumentContainer);
container.CreateIfNotExists();
container = BlobServiceClient.GetBlobContainerClient(FileServiceHelper.TempContainer);
container.CreateIfNotExists();
}
///
/// Speichern einer Datei in einen Container
///
/// Name des Containers
/// Dateiname (inkl. Pfad, wenn gewünscht)
/// Datei als Byte-Array
/// Überschreiben vorhandener Daten
/// Absoluter Dateiname
public async Task StoreAsync(string containerName, string filename, byte[] file, bool overwrite = true)
{
var container = BlobServiceClient.GetBlobContainerClient(containerName);
var blob = container.GetBlockBlobClient(filename);
await using var stream = new MemoryStream(file);
await blob.UploadAsync(stream);
return blob.Name;
}
///
/// Speichern einer Datei in einen Container
///
/// Name des Containers
/// Dateiname (inkl. Pfad, wenn gewünscht)
/// Datei als Stream
/// Überschreiben vorhandener Daten
/// Absoluter Dateiname
public async Task StoreAsync(string containerName, string filename, Stream fileStream, bool overwrite = true)
{
var container = BlobServiceClient.GetBlobContainerClient(containerName);
var blob = container.GetBlockBlobClient(filename);
await blob.UploadAsync(fileStream);
return blob.Name;
}
///
/// Umbenennen einer Datei in einem Container
///
/// Name des Containers
/// Dateiname (inkl. Pfad, wenn gewünscht)
/// Neuer Dateiname
public async Task RenameAsync(string containerName, string filename, string newFilename)
{
var container = BlobServiceClient.GetBlobContainerClient(containerName);
var blob = container.GetBlockBlobClient(filename);
var newBlob = container.GetBlockBlobClient(newFilename);
await newBlob.StartCopyFromUriAsync(blob.Uri);
await blob.DeleteIfExistsAsync();
}
///
/// Gibt eine Datei zurück
///
/// Name des Containers
/// Dateiname (inkl. Pfad, wenn gewünscht)
/// Datei als Byte-Array
public async Task GetAsync(string containerName, string filename)
{
var container = BlobServiceClient.GetBlobContainerClient(containerName);
var blob = container.GetBlockBlobClient(filename);
// Save blob contents to a file.
byte[] result = null;
if (await blob.ExistsAsync())
{
await using var memoryStream = new MemoryStream();
await blob.DownloadToAsync(memoryStream);
result = memoryStream.ToArray();
}
return result;
}
///
/// Gibt eine Datei zurück
///
/// Name des Containers
/// Dateiname (inkl. Pfad, wenn gewünscht)
/// Datei als Stream
public async Task GetAsStreamAsync(string containerName, string filename)
{
var container = BlobServiceClient.GetBlobContainerClient(containerName);
var blob = container.GetBlockBlobClient(filename);
var memoryStream = new MemoryStream();
await blob.DownloadToAsync(memoryStream);
memoryStream.Position = 0;
return memoryStream;
}
///
/// Löschen einer Datei in einem Container
///
/// Name des Containers
/// Dateiname (inkl. Pfad, wenn gewünscht)
public async Task DeleteAsync(string containerName, string filename)
{
var container = BlobServiceClient.GetBlobContainerClient(containerName);
var blob = container.GetBlockBlobClient(filename);
await blob.DeleteIfExistsAsync();
}
///
/// Gibt eine Liste aller Dateien eines Containers zurück die sich in einem Directory befinden
///
/// Name des Containers
/// Verzeichnis.
/// Teil eines Dateinamens für die suche
/// Liste von Dateien
public async Task> ListFilesAsync(string containerName, string directory = "", string fileNamePart = "")
{
var result = new List();
Wildcard wildCard = null;
if (!string.IsNullOrWhiteSpace(fileNamePart))
wildCard = new Wildcard(fileNamePart, RegexOptions.IgnoreCase);
var container = BlobServiceClient.GetBlobContainerClient(containerName);
await foreach (var blobPage in container.GetBlobsByHierarchyAsync(BlobTraits.None, BlobStates.None, prefix: directory).AsPages())
{
// A hierarchical listing may return both virtual directories and blobs.
foreach (var item in blobPage.Values)
{
if (item.IsPrefix)
continue;
if (!item.IsBlob)
continue;
if (wildCard != null)
{
if (wildCard.IsMatch(GetFilename(item.Blob.Name)))
result.Add(item.Blob.Name);
}
else
result.Add(item.Blob.Name);
}
}
return result;
}
///
/// Gibt eine Liste aller Verzeichnise zurück die sich im Container befindne
///
/// Name des Containers
/// wenn angegeben, wird von dem Verzeihnis als root ausgegangen
///
public async Task> ListDirectoriesAsync(string containerName, string root = "")
{
var result = new List();
var container = BlobServiceClient.GetBlobContainerClient(containerName);
await foreach (var blobPage in container.GetBlobsByHierarchyAsync(delimiter: "/", prefix: root).AsPages())
{
result.AddRange(from item in blobPage.Values where item.IsPrefix select item.Prefix);
}
return result;
}
///
/// Koperien von Dateinen eines Containers in einen anderen
///
/// Quellcontainer
/// Quellpfad
/// ZielContainer
/// ZielPfad
public async Task CopyFilesAsync(string sourceContainer, string sourceDirectory, string targetContainer, string targetDirectory)
{
var cloudSourceContainer = BlobServiceClient.GetBlobContainerClient(sourceContainer);
var cloudTargetContainer = BlobServiceClient.GetBlobContainerClient(targetContainer);
var blobs = new List();
await foreach (var blobPage in cloudSourceContainer.GetBlobsByHierarchyAsync(BlobTraits.None, BlobStates.None, prefix: sourceDirectory).AsPages())
{
blobs.AddRange(from item in blobPage.Values where item.IsBlob select item.Blob);
}
foreach (var blobItem in blobs)
{
var sourceClient = cloudSourceContainer.GetBlockBlobClient(blobItem.Name);
var copyClient = cloudTargetContainer.GetBlockBlobClient(blobItem.Name.Replace(sourceDirectory, targetDirectory));
await copyClient.StartCopyFromUriAsync(sourceClient.Uri);
}
}
///
/// Koperien von Dateien eines Pfades in einen anderen
///
/// Name des Containers
/// Quellpfad
/// ZielPfad
public async Task CopyFilesAsync(string containerName, string sourceDirectory, string targetDirectory)
{
await CopyFilesAsync(containerName, sourceDirectory, containerName, targetDirectory);
}
///
/// Verschieben von Dateien eines Containers in einen anderen
///
/// Quellcontainer
/// Quellpfad
/// ZielContainer
/// ZielPfad
public async Task MoveFilesAsync(string sourceContainer, string sourceDirectory, string targetContainer, string targetDirectory)
{
var cloudSourceContainer = BlobServiceClient.GetBlobContainerClient(sourceContainer);
var cloudTargetContainer = BlobServiceClient.GetBlobContainerClient(targetContainer);
var blobs = new List();
await foreach (var blobPage in cloudSourceContainer.GetBlobsByHierarchyAsync(BlobTraits.None, BlobStates.None, prefix: sourceDirectory).AsPages())
{
blobs.AddRange(from item in blobPage.Values where item.IsBlob select item.Blob);
}
foreach (var blobItem in blobs)
{
var sourceClient = cloudSourceContainer.GetBlockBlobClient(blobItem.Name);
var copyClient = cloudTargetContainer.GetBlockBlobClient(blobItem.Name.Replace(sourceDirectory, targetDirectory));
await copyClient.StartCopyFromUriAsync(sourceClient.Uri);
await sourceClient.DeleteAsync();
}
}
///
/// Verschieben von Dateien eines Pfades in einen anderen
///
/// Name des Containers
/// Quellpfad
/// ZielPfad
public async Task MoveFilesAsync(string containerName, string sourceDirectory, string targetDirectory)
{
await MoveFilesAsync(containerName, sourceDirectory, containerName, targetDirectory);
}
///
/// Löschen des Inhalts eines Verzeichnises
///
/// Name des Containers
/// Verzeichnis
/// Optional: Dateinamen Wildcard
public async Task ClearDirectoryAsync(string containerName, string directory, string fileNamePart = "")
{
Wildcard wildCard = null;
if (!string.IsNullOrWhiteSpace(fileNamePart))
wildCard = new Wildcard(fileNamePart, RegexOptions.IgnoreCase);
var container = BlobServiceClient.GetBlobContainerClient(containerName);
await foreach (var blobPage in container.GetBlobsByHierarchyAsync(BlobTraits.None, BlobStates.None, prefix: directory).AsPages())
{
// A hierarchical listing may return both virtual directories and blobs.
foreach (var item in blobPage.Values)
{
if (item.IsPrefix)
continue;
if (!item.IsBlob)
continue;
if (wildCard != null)
{
if (wildCard.IsMatch(GetFilename(item.Blob.Name)))
{
var client = container.GetBlockBlobClient(item.Blob.Name);
await client.DeleteAsync();
}
}
else
{
var client = container.GetBlockBlobClient(item.Blob.Name);
await client.DeleteAsync();
}
}
}
}
///
/// Löscht einen Container und den Inhalt
///
/// Name des Containers
public async Task DeleteContainerAsync(string containerName)
{
var container = BlobServiceClient.GetBlobContainerClient(containerName);
await container.DeleteAsync();
}
///
/// Löscht Dateien aus einem Ordner auf welche
/// vor dem Datum das letzte mal zugegriffen wurde
///
/// Name des Containers
/// Verzeichnis
/// Datum
public async Task DeleteOldFilesAsync(string containerName, string directory, DateTimeOffset date)
{
var container = BlobServiceClient.GetBlobContainerClient(containerName);
await foreach (var blobPage in container.GetBlobsByHierarchyAsync(BlobTraits.None, BlobStates.None, prefix: directory).AsPages())
{
foreach (var item in blobPage.Values)
{
if (item.IsPrefix)
continue;
if (!item.IsBlob)
continue;
var client = container.GetBlockBlobClient(item.Blob.Name);
if (item.Blob.Properties.LastModified < date)
await client.DeleteAsync();
}
}
}
///
/// Gibt den reinen Dateinamen eines Files zurück (Ohne Directories usw)
///
/// Dateiname
/// Reiner Dateiname
public string GetFlatFilename(string fileName)
{
return GetFilename(fileName);
}
#region private
///
/// Gibt den Dateinamen einer Datei ohne lokale Pfadangaben zurück
///
/// Pfad + Dateinamen
/// Dateiname ohne Pfadangaben
private string GetFilename(string path)
{
var fileName = path.Split(new[] { "/" }, StringSplitOptions.None).Last();
return fileName;
}
#endregion
}
///
/// Hilfsklasse für das Finden von Dateien mittels Wildcards
///
[ExcludeFromCodeCoverage]
internal class Wildcard : Regex
{
///
/// Erstellt eine instanz
///
/// Wildcard-Ausdruck
public Wildcard(string pattern) : base(ToRegex(pattern))
{
}
///
/// Erstellt eine Instanz
///
/// Wildcard-Ausdruck
/// Optionen
public Wildcard(string pattern, RegexOptions options) : base(ToRegex(pattern), options)
{
}
///
/// Erstellt einen regulären Ausdruck aus dem Wildcard-Ausdruck
///
/// Wildcard-Ausdruck
/// Wildcard-Ausdruck in Regex konvertiert
public static string ToRegex(string pattern)
{
return "^" + Escape(pattern).Replace("\\*", ".*").Replace("\\?", ".") + "$";
}
}
}