Skip to content

Commit

Permalink
Merge pull request #1564 from tedvanderveen/master
Browse files Browse the repository at this point in the history
Use Azure.Storage.Blobs Nuget package to replace deprecated Microsoft.Azure.Storage.Blob
  • Loading branch information
tidyui committed Oct 8, 2021
2 parents 0b258bb + a881b58 commit ad4d354
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 214 deletions.
156 changes: 94 additions & 62 deletions core/Piranha.Azure.BlobStorage/BlobStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,22 @@
*
*/

using Microsoft.Azure.Storage;
using Microsoft.Azure.Storage.Auth;
using Microsoft.Azure.Storage.Blob;
using System;
using System.IO;
using System.Threading.Tasks;
using Azure.Core;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Piranha.Models;

namespace Piranha.Azure
{
public class BlobStorage : IStorage
public class BlobStorage : IStorage, IStorageSession, IInitializable
{
/// <summary>
/// The private storage account.
/// </summary>
private readonly CloudStorageAccount _storage;

/// <summary>
/// The name of the container to use.
/// </summary>
private readonly string _containerName;

/// <summary>
/// The container url.
/// </summary>
private string _containerUrl;
private readonly BlobContainerClient _blobContainerClient;

/// <summary>
/// How uploaded files should be named to
Expand All @@ -42,16 +34,18 @@ public class BlobStorage : IStorage
/// <summary>
/// Creates a new Blog Storage service from the given credentials.
/// </summary>
/// <param name="credentials">The connection credentials</param>
/// <param name="containerName">The container name</param>
/// <param name="blobContainerUri">
/// A <see cref="Uri"/> referencing the blob service.
/// This is likely to be similar to "https://{account_name}.blob.core.windows.net".
/// </param>
/// <param name="tokenCredential">The connection credentials</param>
/// <param name="naming">How uploaded media files should be named</param>
public BlobStorage(
StorageCredentials credentials,
string containerName = "uploads",
Uri blobContainerUri,
TokenCredential tokenCredential,
BlobStorageNaming naming = BlobStorageNaming.UniqueFileNames)
{
_storage = new CloudStorageAccount(credentials, true);
_containerName = containerName;
_blobContainerClient = new BlobContainerClient(blobContainerUri, tokenCredential);
_naming = naming;
}

Expand All @@ -66,31 +60,13 @@ public BlobStorage(
string containerName = "uploads",
BlobStorageNaming naming = BlobStorageNaming.UniqueFileNames)
{
_storage = CloudStorageAccount.Parse(connectionString);
_containerName = containerName;
_blobContainerClient = new BlobContainerClient(connectionString, containerName);
_naming = naming;
}

/// <summary>
/// Opens a new storage session.
/// </summary>
/// <returns>A new open session</returns>
public async Task<IStorageSession> OpenAsync()
public Task<IStorageSession> OpenAsync()
{
var session = _storage.CreateCloudBlobClient();
var container = session.GetContainerReference(_containerName);

if (!await container.ExistsAsync())
{
await container.CreateAsync();
await container.SetPermissionsAsync(new BlobContainerPermissions
{
PublicAccess = BlobContainerPublicAccessType.Blob
});
}
_containerUrl = container.Uri.AbsoluteUri;

return new BlobStorageSession(this, container, _naming);
return Task.FromResult<IStorageSession>(this);
}

/// <summary>
Expand All @@ -101,18 +77,7 @@ await container.SetPermissionsAsync(new BlobContainerPermissions
/// <returns>The public url</returns>
public string GetPublicUrl(Media media, string id)
{
if (media != null && !string.IsNullOrWhiteSpace(id))
{
if (string.IsNullOrEmpty(_containerUrl))
{
var session = _storage.CreateCloudBlobClient();
var container = session.GetContainerReference(_containerName);

_containerUrl = container.Uri.AbsoluteUri;
}
return $"{ _containerUrl }/{ GetResourceName(media, id, true) }";
}
return null;
return string.IsNullOrWhiteSpace(id) ? default : $"{_blobContainerClient.Uri.AbsoluteUri}/{GetResourceName(media, id, true)}";
}

/// <summary>
Expand All @@ -135,14 +100,81 @@ public string GetResourceName(Media media, string filename)
/// <returns>The public url</returns>
public string GetResourceName(Media media, string filename, bool encode)
{
if (_naming == BlobStorageNaming.UniqueFileNames)
{
return $"{ media.Id }-{ (encode ? System.Web.HttpUtility.UrlPathEncode(filename) : filename) }";
}
else
{
return $"{ media.Id }/{ (encode ? System.Web.HttpUtility.UrlPathEncode(filename) : filename) }";
}
return _naming == BlobStorageNaming.UniqueFileNames ? $"{media.Id}-{(encode ? System.Web.HttpUtility.UrlPathEncode(filename) : filename)}" : $"{media.Id}/{(encode ? System.Web.HttpUtility.UrlPathEncode(filename) : filename)}";
}

/// <summary>
/// Writes the content for the specified media content to the given stream.
/// </summary>
/// <param name="media">The media file</param>
/// <param name="filename">The file name</param>
/// <param name="stream">The output stream</param>
/// <returns>If the media was found</returns>
public async Task<bool> GetAsync(Media media, string filename, Stream stream)
{
var blob = _blobContainerClient.GetBlobClient(GetResourceName(media, filename));

return await blob.ExistsAsync() && (await blob.DownloadToAsync(stream)).Status.IsSuccessStatusCode();
}

/// <summary>
/// Stores the given media content.
/// </summary>
/// <param name="media">The media file</param>
/// <param name="filename">The file name</param>
/// <param name="contentType">The content type</param>
/// <param name="stream">The input stream</param>
/// <returns>The public URL</returns>
public async Task<string> PutAsync(Media media, string filename, string contentType, Stream stream)
{
var blob = _blobContainerClient.GetBlobClient(GetResourceName(media, filename));

var blobHttpHeader = new BlobHttpHeaders {ContentType = contentType};

await blob.UploadAsync(stream, blobHttpHeader);

return blob.Uri.AbsoluteUri;
}

/// <summary>
/// Stores the given media content.
/// </summary>
/// <param name="media">The media file</param>
/// <param name="filename">The file name</param>
/// <param name="contentType">The content type</param>
/// <param name="bytes">The binary data</param>
/// <returns>The public URL</returns>
public async Task<string> PutAsync(Media media, string filename, string contentType, byte[] bytes)
{
return await PutAsync(media, filename, contentType, new MemoryStream(bytes));
}

/// <summary>
/// Deletes the content for the specified media.
/// </summary>
/// <param name="media">The media file</param>
/// <param name="filename">The file name</param>
public async Task<bool> DeleteAsync(Media media, string filename)
{
var blob = _blobContainerClient.GetBlobClient(GetResourceName(media, filename));

return await blob.DeleteIfExistsAsync();
}

/// <summary>
/// Initialize the Blob Storage service by ensuring that the Blob Container exists.
/// </summary>
public void Init()
{
_blobContainerClient.CreateIfNotExists(PublicAccessType.Blob);
}

/// <summary>
/// Disposes the session.
/// </summary>
public void Dispose()
{
GC.SuppressFinalize(this);
}
}
}
35 changes: 23 additions & 12 deletions core/Piranha.Azure.BlobStorage/BlobStorageExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
*
*/

using System;
using Azure.Core;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Azure.Storage.Auth;
using Piranha;
using Piranha.Azure;

Expand All @@ -19,23 +20,28 @@ public static class BlobStorageExtensions
/// Adds the Azure BlobStorage module.
/// </summary>
/// <param name="serviceBuilder">The service builder</param>
/// <param name="credentials">The auth credentials</param>
/// <param name="containerName">The optional container name</param>
/// <param name="credential">
/// The token credential used to sign requests.
/// </param>
/// <param name="blobContainerUri">
/// A <see cref="Uri"/> referencing the blob service.
/// This is likely to be similar to "https://{account_name}.blob.core.windows.net".
/// </param>
/// <param name="naming">How uploaded media files should be named</param>
/// <param name="scope">The optional service scope. Default is singleton</param>
/// <returns>The service collection</returns>
public static PiranhaServiceBuilder UseBlobStorage(
this PiranhaServiceBuilder serviceBuilder,
StorageCredentials credentials,
string containerName = "uploads",
Uri blobContainerUri,
TokenCredential credential,
BlobStorageNaming naming = BlobStorageNaming.UniqueFileNames,
ServiceLifetime scope = ServiceLifetime.Singleton)
{
serviceBuilder.Services.AddPiranhaBlobStorage(credentials, containerName, naming, scope);
serviceBuilder.Services.AddPiranhaBlobStorage(blobContainerUri, credential, naming, scope);

return serviceBuilder;
}

/// <summary>
/// Adds the Azure BlobStorage module.
/// </summary>
Expand All @@ -61,22 +67,27 @@ public static PiranhaServiceBuilder UseBlobStorage(
/// Adds the services for the Azure BlobStorage service.
/// </summary>
/// <param name="services">The current service collection</param>
/// <param name="credentials">The auth credentials</param>
/// <param name="containerName">The optional container name</param>
/// <param name="credential">
/// The token credential used to sign requests.
/// </param>
/// <param name="blobContainerUri">
/// A <see cref="Uri"/> referencing the blob service.
/// This is likely to be similar to "https://{account_name}.blob.core.windows.net".
/// </param>
/// <param name="naming">How uploaded media files should be named</param>
/// <param name="scope">The optional service scope. Default is singleton</param>
/// <returns>The service collection</returns>
public static IServiceCollection AddPiranhaBlobStorage(
this IServiceCollection services,
StorageCredentials credentials,
string containerName = "uploads",
Uri blobContainerUri,
TokenCredential credential,
BlobStorageNaming naming = BlobStorageNaming.UniqueFileNames,
ServiceLifetime scope = ServiceLifetime.Singleton)
{
App.Modules.Register<BlobStorageModule>();

services.Add(new ServiceDescriptor(typeof(IStorage), sp =>
new BlobStorage(credentials, containerName, naming), scope));
new BlobStorage(blobContainerUri, credential, naming), scope));

return services;
}
Expand Down
Loading

0 comments on commit ad4d354

Please sign in to comment.