Azure Blob Storage klient i ASP.NET Core

I det här inlägget beskrivs hur du kan skapa en Azure Blob Storage klient i ASP.NET Core som kan användas för att kommunicera med ditt blobblagringskonto. Blobblagring kan användas för att lagra och servera bilder, videor, ljud och textfiler.

Azure Blob Storage är en molntjänst som kan användas för att lagra massiva mängder ostrukturerad data som filer eller blobbar (Binary Large Object ). Azure Blob Storage skalas automatiskt för att möjliggöra snabb uppladdningshastighet, snabb nedladdningshastighet och en obegränsad mängd lagringsutrymme.

Blobblagring är avsedd för visning av bilder eller dokument direkt i en webbläsare, lagring av filer för distribuerad åtkomst, streaming av video och ljud, skrivning till loggfiler, lagring av data för säkerhetskopiering och återställning, katastrofåterställning, arkivering, lagring av data för analys.

Inställningar

Vi behöver först installera ett NuGet-paket (Microsoft.Azure.Storage.Blob eller WindowsAzure.Storage) till vårt projekt i Visual Studio. Vi lagrar en anslutningssträng till Azure Blob Storage som applikationsinställningar i secrets.json och appsettings.json. Vi lagrar även namn på behållare, vi kan ha flera behållare och använda olika namn vid produktion respektive utveckling.

{
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Information"
    }
  },
  "BlobStorageOptions": {
    "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=XXXXXXX;AccountKey=XXXXXXXXXXXXX;EndpointSuffix=core.windows.net;",
    "Containers": {
      "files": "test-files",
      "media": "media"
    }
  }
}
public class BlobStorageOptions
{
    #region Variables

    public string ConnectionString { get; set; }
    public IDictionary<string, string> Containers { get; set; }

    #endregion

    #region Constructors

    public BlobStorageOptions()
    {
        // Set values for instance variables
        this.ConnectionString = "";
        this.Containers = new Dictionary<string, string>();

    } // End of the constructor

    #endregion

} // End of the class

Tjänster

Vi behöver registrera blobblagringsinställningar och vår blobblagringsklient i klassen StartUp i vårt projekt.

public void ConfigureServices(IServiceCollection services)
{
    // Add the mvc framework
    services.AddRazorPages();

    // Create options
    services.Configure<BlobStorageOptions>(configuration.GetSection("BlobStorageOptions"));

    // Add repositories
    services.AddSingleton<IBlobStorageRepository, BlobStorageRepository>();

} // End of the ConfigureServices method

Gränssnitt

public interface IBlobStorageRepository
{
    Task<CloudBlockBlob> UploadFromStream(string container_name, string blob_name, Stream stream);
    Task<Stream> GetWriteStream(string container_name, string blob_name);
    Task UploadChunk(string container_name, string blob_name, string block_id, Stream stream);
    Task<CloudBlockBlob> UploadChunkList(string container_name, string blob_name, string md5, IList<string> chunks);
    Task DownloadToStream(string container_name, string blob_name, Stream stream);
    Task DownloadRangeToStream(CloudBlockBlob blob, Stream stream, long? offset, long? length);
    Task<Stream> GetReadStream(string container_name, string blob_name);
    string GetReadableSasUri(string container_name, string blob_name, string filename, string encoding);
    string GetWriteableSasUri(string container_name, string blob_name, string ip_address = null);
    string GetBlobUrl(string container_name, string blob_name);
    Task<CloudBlockBlob> GetBlobAttributes(string container_name, string blob_name);
    Task Delete(string container_name, string blob_name);

} // End of the interface

Klass

public class BlobStorageRepository : IBlobStorageRepository
{
    #region Variables

    private readonly ILogger logger;
    private readonly BlobStorageOptions options;
    private readonly CloudBlobClient client;

    #endregion

    #region Constructors

    public BlobStorageRepository(ILogger<BlobStorageRepository> logger, IOptions<BlobStorageOptions> options)
    {
        // Set values for instance variables
        this.logger = logger;
        this.options = options.Value;

        // Get a storage account
        CloudStorageAccount account = CloudStorageAccount.Parse(this.options.ConnectionString);

        // Get a client
        this.client = account.CreateCloudBlobClient();

    } // End of the constructor

    #endregion

    #region Add methods

    public async Task<CloudBlockBlob> UploadFromStream(string container_name, string blob_name, Stream stream)
    {
        // Get a container reference
        CloudBlobContainer container = GetContainerReference(container_name);

        // Get a blob reference
        CloudBlockBlob blob = container.GetBlockBlobReference(blob_name);

        // Catch exceptions to make sure that the stream is disposed
        try
        {
            // Write to the blob 
            await blob.UploadFromStreamAsync(stream);
        }
        catch(Exception ex)
        {
            // Log the exception
            logger.LogError(ex, $"UploadFromStream: {blob_name}", null);
        }
        finally
        {
            // Dispose of the stream
            stream.Dispose();
        }
            
        // Fetch blob properties
        await blob.FetchAttributesAsync();

        // Return the blob
        return blob;

    } // End of the UploadFromStream method

    public async Task<Stream> GetWriteStream(string container_name, string blob_name)
    {
        // Get a container reference
        CloudBlobContainer container = GetContainerReference(container_name);

        // Get a blob object
        CloudBlockBlob blob = container.GetBlockBlobReference(blob_name);
        blob.StreamWriteSizeInBytes = 500 * 1024;

        //blockBlob.Properties.ContentType = contentType;

        // Create a stream
        CloudBlobStream stream = null;

        try
        {
            stream = await blob.OpenWriteAsync();
        }
        catch(Exception ex)
        {
            // Log the exception
            logger.LogError(ex, $"GetWriteStream: {blob_name}", null);
        }

        // Return a stream
        return stream;

    } // End of the GetWriteStream method

    public async Task UploadChunk(string container_name, string blob_name, string block_id, Stream stream)
    {
        // Get a container reference
        CloudBlobContainer container = GetContainerReference(container_name);

        // Get a blob reference
        CloudBlockBlob blob = container.GetBlockBlobReference(blob_name);

        // Catch exceptions to make sure that the stream is disposed
        try
        {
            // Write to the blob 
            await blob.PutBlockAsync(block_id, stream, null);
        }
        catch (Exception ex)
        {
            // Log the exception
            logger.LogError(ex, $"UploadChunk: {blob_name}", null);
        }
        finally
        {
            // Dispose of the stream
            stream.Dispose();
        }

    } // End of the UploadChunk method

    public async Task<CloudBlockBlob> UploadChunkList(string container_name, string blob_name, string md5, IList<string> chunks)
    {
        // Get a container reference
        CloudBlobContainer container = GetContainerReference(container_name);

        // Get a blob reference
        CloudBlockBlob blob = container.GetBlockBlobReference(blob_name);

        // Catch exceptions to make sure that the stream is disposed
        try
        {
            // Upload a list with block id
            blob.Properties.ContentMD5 = md5;
            await blob.PutBlockListAsync(chunks);
        }
        catch (Exception ex)
        {
            // Log the exception
            logger.LogError(ex, $"UploadChunkList: {blob_name}", null);
        }

        // Fetch blob properties
        await blob.FetchAttributesAsync();

        // Return the blob
        return blob;

    } // End of the UploadChunkList method

    #endregion

    #region Get methods

    public async Task DownloadToStream(string container_name, string blob_name, Stream stream)
    {
        // Get a container reference
        CloudBlobContainer container = GetContainerReference(container_name);

        // Get a blob object
        CloudBlockBlob blob = container.GetBlockBlobReference(blob_name);

        // Download the blob to a stream
        try
        {
            await blob.DownloadToStreamAsync(stream);
        }
        catch(Exception ex)
        {
            // Log the exception
            logger.LogError(ex, $"DownloadToStream: {blob_name}", null);
        }
           
    } // End of the DownloadToStream method

    public async Task DownloadRangeToStream(CloudBlockBlob blob, Stream stream, long? offset, long? length)
    {
        // Download the blob to a stream
        try
        {
            await blob.DownloadRangeToStreamAsync(stream, offset, length);
        }
        catch (Exception ex)
        {
            // Log the exception
            logger.LogError(ex, $"DownloadRangeToStream", null);
        }

    } // End of the DownloadRangeToStream method

    public async Task<Stream> GetReadStream(string container_name, string blob_name)
    {
        // Get a container reference
        CloudBlobContainer container = GetContainerReference(container_name);

        // Get a blob object
        CloudBlockBlob blob = container.GetBlockBlobReference(blob_name);
        blob.StreamMinimumReadSizeInBytes = 500 * 1024;

        // Create a stream
        Stream stream = null;

        try
        {
            stream = await blob.OpenReadAsync();
        }
        catch (Exception ex)
        {
            // Log the exception
            logger.LogError(ex, $"GetReadStream: {blob_name}", null);
        }

        // Return the stream
        return stream;

    } // End of the GetReadStream method

    public string GetReadableSasUri(string container_name, string blob_name, string filename, string encoding)
    {
        // Get a container reference
        CloudBlobContainer container = GetContainerReference(container_name);

        // Get a blob object
        CloudBlockBlob blob = container.GetBlockBlobReference(blob_name);

        // Set content type
        string content_type = MimeTypes.GetMimeType(filename);
        if (encoding == "ascii" || encoding == "utf-8" || encoding == "utf-16" || encoding == "utf-32")
        {
            content_type += "; charset=" + encoding;
        }

        // Create a SAS token
        string sasToken = blob.GetSharedAccessSignature(new SharedAccessBlobPolicy()
        {
            // Assuming the blob can be downloaded in 5 minutes
            Permissions = SharedAccessBlobPermissions.Read,
            SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(5)

        }, new SharedAccessBlobHeaders()
        {
            ContentDisposition = "attachment; filename=" + filename,
            ContentType = content_type

        }, null, SharedAccessProtocol.HttpsOnly, null);

        // Return the url
        return blob.Uri + sasToken;

    } // End of the GetReadableSasUri method

    public string GetWriteableSasUri(string container_name, string blob_name, string ip_address = null)
    {
        // Get a container reference
        CloudBlobContainer container = GetContainerReference(container_name);

        // Create an ip range
        IPAddressOrRange ip_range = string.IsNullOrEmpty(ip_address) == false ? new IPAddressOrRange(ip_address) : null;

        // Create a SAS token
        string sasToken = container.GetSharedAccessSignature(new SharedAccessBlobPolicy()
        {
            // Assuming the blob can be created in 24 hours 
            Permissions = SharedAccessBlobPermissions.Read | SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Create | SharedAccessBlobPermissions.Add | SharedAccessBlobPermissions.Delete,
            SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24)

        }, null, SharedAccessProtocol.HttpsOnly, ip_range);

        // Return the url
        return container.Uri + "/" + blob_name + sasToken;

    } // End of the GetWriteableSasUri method

    public string GetBlobUrl(string container_name, string blob_name)
    {
        // Get the container name from the dictionary
        container_name = this.options.Containers[container_name];

        // Return the url
        return "https://mysite.blob.core.windows.net/" + container_name + "/" + blob_name;

    } // End of the GetBlobUrl method

    public async Task<CloudBlockBlob> GetBlobAttributes(string container_name, string blob_name)
    {
        // Get a container reference
        CloudBlobContainer container = GetContainerReference(container_name);

        // Get a blob reference
        CloudBlockBlob blob = container.GetBlockBlobReference(blob_name);

        // Fetch blob properties
        await blob.FetchAttributesAsync();

        // Return the blob
        return blob;

    } // End of the GetBlobAttributes method

    #endregion

    #region Delete methods

    public async Task Delete(string container_name, string blob_name)
    {
        // Get a container reference
        CloudBlobContainer container = GetContainerReference(container_name);

        // Get a blob object
        CloudBlockBlob blob = container.GetBlockBlobReference(blob_name);

        // Delete the blob
        try
        {
            await blob.DeleteIfExistsAsync();
        }
        catch(Exception ex)
        {
            // Log the exception
            logger.LogError(ex, $"Delete blob: {blob_name}", null);
        }
            
    } // End of the Delete method

    #endregion

    #region Helper methods

    private CloudBlobContainer GetContainerReference(string name)
    {
        // Get the name from the dictionary
        name = this.options.Containers[name];

        // Get a reference to a cloud blob contaner
        CloudBlobContainer container = this.client.GetContainerReference(name);

        // Create the container if it doesn't exist
        //await container.CreateIfNotExistsAsync();

        // Return the container reference
        return container;

    } // End of the GetContainerReference method

    #endregion

} // End of the class

Lämna ett svar

E-postadressen publiceras inte. Obligatoriska fält är märkta *