-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #195 from Avanade/feature/updateFrameworkVersion
Feature/update framework version
- Loading branch information
Showing
14 changed files
with
600 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# CI & CD workflow | ||
name: CI/CD - Liquid.Adapter.AzureStorage component for Liquid Application Framework | ||
|
||
on: | ||
push: | ||
branches: [ main ] | ||
paths: | ||
- 'src/Liquid.Adapter.AzureStorage/**' | ||
|
||
pull_request: | ||
branches: [ main, releases/** ] | ||
types: [opened, synchronize, reopened] | ||
paths: | ||
- 'src/Liquid.Adapter.AzureStorage/**' | ||
|
||
# Allows you to run this workflow manually from the Actions tab | ||
workflow_dispatch: | ||
|
||
jobs: | ||
call-reusable-build-workflow: | ||
uses: Avanade/Liquid-Application-Framework/.github/workflows/base-liquid-ci-and-cd.yml@main | ||
with: | ||
component_name: Liquid.Adapter.AzureStorage | ||
secrets: | ||
sonar_token: ${{ secrets.SONAR_TOKEN_STORAGE }} | ||
nuget_token: ${{ secrets.PUBLISH_TO_NUGET_ORG }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
using Azure.Core; | ||
using Azure.Storage.Blobs; | ||
using Microsoft.Extensions.Options; | ||
|
||
namespace Liquid.Adapter.AzureStorage | ||
{ | ||
///<inheritdoc/> | ||
public class BlobClientFactory : IBlobClientFactory | ||
{ | ||
private readonly StorageSettings _options; | ||
private IList<BlobContainerClient> _clients = new List<BlobContainerClient>(); | ||
Check warning on line 11 in src/Liquid.Adapter.AzureStorage/BlobClientFactory.cs GitHub Actions / call-reusable-build-workflow / build
|
||
|
||
///<inheritdoc/> | ||
public IList<BlobContainerClient> Clients => _clients; | ||
|
||
/// <summary> | ||
/// Inicialize a new instance of <see cref="BlobClientFactory"/> | ||
/// </summary> | ||
/// <param name="options">Configurations set.</param> | ||
/// <exception cref="ArgumentNullException"></exception> | ||
public BlobClientFactory(IOptions<StorageSettings>? options) | ||
{ | ||
_options = options?.Value ?? throw new ArgumentNullException(nameof(options)); | ||
} | ||
|
||
///<inheritdoc/> | ||
public List<BlobContainerClient> SetContainerClients() | ||
{ | ||
if(_options.Containers.Count == 0) | ||
throw new ArgumentNullException(nameof(_options)); | ||
Check warning on line 30 in src/Liquid.Adapter.AzureStorage/BlobClientFactory.cs GitHub Actions / call-reusable-build-workflow / build
|
||
|
||
var clients = new List<BlobContainerClient>(); | ||
|
||
foreach(var container in _options.Containers) | ||
{ | ||
var client = new BlobContainerClient(container.ConnectionString,container.ContainerName); | ||
|
||
clients.Add(client); | ||
} | ||
|
||
return clients; | ||
} | ||
|
||
///<inheritdoc/> | ||
public BlobContainerClient GetContainerClient(string containerName) | ||
{ | ||
var client = _clients.FirstOrDefault(x => x.Name == containerName); | ||
|
||
if (client == null) { | ||
throw new ArgumentException(nameof(containerName)); | ||
} | ||
|
||
return client; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
using Azure.Storage.Blobs.Models; | ||
using Azure.Storage.Blobs.Specialized; | ||
using Azure.Storage.Sas; | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Text; | ||
|
||
namespace Liquid.Adapter.AzureStorage | ||
{ | ||
///<inheritdoc/> | ||
[ExcludeFromCodeCoverage] | ||
public class BlobStorageAdapter : ILiquidBlobStorageAdapter | ||
{ | ||
private readonly IBlobClientFactory _factory; | ||
|
||
/// <summary> | ||
/// Initialize a new instance of <see cref="BlobStorageAdapter"/> | ||
/// </summary> | ||
/// <param name="factory"></param> | ||
/// <exception cref="ArgumentNullException"></exception> | ||
public BlobStorageAdapter(IBlobClientFactory factory) | ||
{ | ||
_factory = factory ?? throw new ArgumentNullException(nameof(factory)); | ||
|
||
_factory.SetContainerClients(); | ||
} | ||
|
||
///<inheritdoc/> | ||
public async Task DeleteByTags(IDictionary<string, string> tags, string containerName) | ||
{ | ||
var client = _factory.GetContainerClient(containerName); | ||
|
||
var stringFilter = string.Empty; | ||
|
||
foreach (var tag in tags) | ||
{ | ||
stringFilter += @$"""{tag.Key}"" = '{tag.Value}' AND "; | ||
Check warning on line 36 in src/Liquid.Adapter.AzureStorage/BlobStorageAdapter.cs GitHub Actions / call-reusable-build-workflow / build
|
||
} | ||
|
||
stringFilter = stringFilter.Substring(0, stringFilter.Length - 4); | ||
|
||
await foreach (TaggedBlobItem blobItem in client.FindBlobsByTagsAsync(stringFilter)) | ||
{ | ||
var blockBlob = client.GetBlockBlobClient(blobItem.BlobName); | ||
|
||
await blockBlob.DeleteAsync(); | ||
}; | ||
Check warning on line 46 in src/Liquid.Adapter.AzureStorage/BlobStorageAdapter.cs GitHub Actions / call-reusable-build-workflow / build
|
||
} | ||
|
||
///<inheritdoc/> | ||
public async Task<List<LiquidBlob>> GetAllBlobs(string containerName) | ||
{ | ||
var client = _factory.GetContainerClient(containerName); | ||
|
||
var results = new List<LiquidBlob>(); | ||
|
||
await foreach (var blobItem in client.GetBlobsAsync()) | ||
{ | ||
var blockBlob = client.GetBlockBlobClient(blobItem.Name); | ||
var blob = await blockBlob.DownloadContentAsync(); | ||
|
||
var item = new LiquidBlob | ||
{ | ||
Blob = Encoding.UTF8.GetString(blob.Value.Content.ToArray()), | ||
Name = blobItem.Name | ||
}; | ||
results.Add(item); | ||
} | ||
|
||
return results; | ||
} | ||
|
||
///<inheritdoc/> | ||
public async Task Delete(string id, string containerName) | ||
{ | ||
var client = _factory.GetContainerClient(containerName); | ||
|
||
var blobClient = client.GetBlobClient(id); | ||
|
||
await blobClient.DeleteAsync(); | ||
} | ||
|
||
///<inheritdoc/> | ||
public async Task<List<LiquidBlob>> ReadBlobsByTags(IDictionary<string, string> tags, string containerName) | ||
{ | ||
var client = _factory.GetContainerClient(containerName); | ||
|
||
var stringFilter = string.Empty; | ||
foreach (var tag in tags) | ||
{ | ||
stringFilter += @$"""{tag.Key}"" = '{tag.Value}' AND "; | ||
Check warning on line 90 in src/Liquid.Adapter.AzureStorage/BlobStorageAdapter.cs GitHub Actions / call-reusable-build-workflow / build
|
||
} | ||
stringFilter = stringFilter.Substring(0, stringFilter.Length - 4); | ||
|
||
var results = new List<LiquidBlob>(); | ||
await foreach (TaggedBlobItem blobItem in client.FindBlobsByTagsAsync(stringFilter)) | ||
{ | ||
var blockBlob = client.GetBlockBlobClient(blobItem.BlobName); | ||
var blob = await blockBlob.DownloadContentAsync(); | ||
var item = new LiquidBlob | ||
{ | ||
Blob = Encoding.UTF8.GetString(blob.Value.Content.ToArray()), | ||
Tags = blockBlob.GetTags().Value.Tags, | ||
Name = blobItem.BlobName | ||
}; | ||
results.Add(item); | ||
} | ||
return results; | ||
} | ||
|
||
///<inheritdoc/> | ||
public async Task UploadBlob(string data, string name, string containerName, IDictionary<string, string>? tags = null) | ||
{ | ||
var client = _factory.GetContainerClient(containerName); | ||
|
||
var blockBlob = client.GetBlockBlobClient(name); | ||
|
||
var options = new BlobUploadOptions() | ||
{ | ||
Tags = tags | ||
}; | ||
await blockBlob.UploadAsync(new MemoryStream(Encoding.UTF8.GetBytes(data)), options); | ||
} | ||
|
||
///<inheritdoc/> | ||
public async Task<LiquidBlob> ReadBlobsByName(string blobName, string containerName) | ||
{ | ||
var client = _factory.GetContainerClient(containerName); | ||
|
||
var blockBlob = client.GetBlockBlobClient(blobName); | ||
var blob = await blockBlob.DownloadContentAsync(); | ||
var item = new LiquidBlob | ||
{ | ||
Blob = Encoding.UTF8.GetString(blob.Value.Content.ToArray()), | ||
Tags = blockBlob.GetTags().Value.Tags, | ||
Name = blobName | ||
}; | ||
|
||
return item; | ||
} | ||
|
||
///<inheritdoc/> | ||
public string? GetBlobSasUri(string blobName, string containerName, DateTimeOffset expiresOn, BlobContainerSasPermissions permissions) | ||
{ | ||
var blobClient = _factory.GetContainerClient(containerName); | ||
|
||
if (!blobClient.CanGenerateSasUri) | ||
{ | ||
return null; | ||
} | ||
|
||
var sasBuilder = new BlobSasBuilder() | ||
{ | ||
BlobContainerName = blobClient.Name, | ||
BlobName = blobName, | ||
Resource = "b" | ||
}; | ||
|
||
sasBuilder.ExpiresOn = expiresOn; | ||
sasBuilder.SetPermissions(permissions); | ||
|
||
var sasURI = blobClient.GenerateSasUri(sasBuilder); | ||
|
||
return sasURI.AbsolutePath; | ||
} | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
src/Liquid.Adapter.AzureStorage/Extensions/IServiceCollectionExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using System.Diagnostics.CodeAnalysis; | ||
|
||
namespace Liquid.Adapter.AzureStorage.Extensions | ||
{ | ||
/// <summary> | ||
/// Extension methods of <see cref="IServiceCollection"/> | ||
/// for register Liquid Azure Storage services. | ||
/// </summary> | ||
[ExcludeFromCodeCoverage] | ||
public static class IServiceCollectionExtensions | ||
{ | ||
/// <summary> | ||
/// Registers <see cref="BlobStorageAdapter"/> service, it's dependency | ||
/// <see cref="BlobClientFactory"/>, and also set configuration | ||
/// option <see cref="StorageSettings"/>. | ||
/// </summary> | ||
/// <param name="services">service collection instance.</param> | ||
/// <param name="configSection">configuration section of storage settings.</param> | ||
public static IServiceCollection AddLiquidAzureStorageAdapter(this IServiceCollection services, string configSection) | ||
{ | ||
services.AddOptions<StorageSettings>() | ||
.Configure<IConfiguration>((settings, configuration) => | ||
{ | ||
configuration.GetSection(configSection).Bind(settings); | ||
}); | ||
|
||
services.AddTransient<IBlobClientFactory, BlobClientFactory>(); | ||
|
||
services.AddSingleton<ILiquidBlobStorageAdapter, BlobStorageAdapter>(); | ||
|
||
return services; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
using Azure.Storage.Blobs; | ||
|
||
namespace Liquid.Adapter.AzureStorage | ||
{ | ||
/// <summary> | ||
/// <see cref="BlobContainerClient"/> instances factory. | ||
/// </summary> | ||
public interface IBlobClientFactory | ||
{ | ||
/// <summary> | ||
/// List of instances of <see cref="BlobContainerClient"/>. | ||
/// </summary> | ||
IList<BlobContainerClient> Clients { get; } | ||
|
||
/// <summary> | ||
/// Initialize an instance of <see cref="BlobContainerClient"/> | ||
/// for each container on the <see cref="StorageSettings"/> and | ||
/// add to <see cref="Clients"/>. | ||
/// </summary> | ||
List<BlobContainerClient> SetContainerClients(); | ||
|
||
/// <summary> | ||
/// Get an instance of <see cref="BlobContainerClient"/> | ||
/// by name. | ||
/// </summary> | ||
/// <param name="containerName"></param> | ||
/// <returns></returns> | ||
BlobContainerClient GetContainerClient(string containerName); | ||
} | ||
} |
Oops, something went wrong.