Browse Source

applied Sebastian's recommended changes

pull/76/head
pushrbx 9 years ago
parent
commit
058e406c80
  1. 2
      Squidex.sln
  2. 0
      src/Squidex.Infrastructure.Azure/Squidex.Infrastructure.Azure.csproj
  3. 90
      src/Squidex.Infrastructure.Azure/Storage/AzureBlobAssetStore.cs
  4. 2
      src/Squidex.Infrastructure.Azure/Storage/AzureStorageException.cs
  5. 5
      src/Squidex.Infrastructure.Azure/Storage/IStorageAccountManager.cs
  6. 9
      src/Squidex.Infrastructure.Azure/Storage/StorageAccountManager.cs
  7. 147
      src/Squidex.Infrastructure.AzureStorage/AzureBlobAssetStore.cs
  8. 33
      src/Squidex.Infrastructure.AzureStorage/BlobContainerProvider.cs
  9. 18
      src/Squidex.Infrastructure.AzureStorage/IBlobContainerProvider.cs
  10. 8
      src/Squidex/Config/Domain/AssetStoreModule.cs
  11. 2
      src/Squidex/Squidex.csproj

2
Squidex.sln

@ -58,7 +58,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Squidex.Domain.Users.Tests"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Squidex.Infrastructure.GetEventStore", "src\Squidex.Infrastructure.GetEventStore\Squidex.Infrastructure.GetEventStore.csproj", "{EF75E488-1324-4E18-A1BD-D3A05AE67B1F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Squidex.Infrastructure.AzureStorage", "src\Squidex.Infrastructure.AzureStorage\Squidex.Infrastructure.AzureStorage.csproj", "{7931187E-A1E6-4F89-8BC8-20A1E445579F}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Squidex.Infrastructure.Azure", "src\Squidex.Infrastructure.Azure\Squidex.Infrastructure.Azure.csproj", "{7931187E-A1E6-4F89-8BC8-20A1E445579F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution

0
src/Squidex.Infrastructure.AzureStorage/Squidex.Infrastructure.AzureStorage.csproj → src/Squidex.Infrastructure.Azure/Squidex.Infrastructure.Azure.csproj

90
src/Squidex.Infrastructure.Azure/Storage/AzureBlobAssetStore.cs

@ -0,0 +1,90 @@
// ==========================================================================
// AzureBlobAssetStore.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.Storage.Blob;
using Squidex.Infrastructure.Assets;
namespace Squidex.Infrastructure.Azure.Storage
{
public class AzureBlobAssetStore : IAssetStore, IExternalSystem
{
private readonly IStorageAccountManager azureStorageAccount;
private readonly string containerName;
private CloudBlobContainer blobContainer;
private const string AssetVersion = "AssetVersion";
private const string AssetId = "AssetId";
public AzureBlobAssetStore(IStorageAccountManager azureStorageAccount, string containerName)
{
Guard.NotNullOrEmpty(containerName, nameof(containerName));
Guard.NotNull(azureStorageAccount, nameof(azureStorageAccount));
this.azureStorageAccount = azureStorageAccount;
this.containerName = containerName;
}
public async Task DownloadAsync(string id, long version, string suffix, Stream stream)
{
var blobName = GetObjectName(id, version, suffix);
var blob = blobContainer.GetBlockBlobReference(blobName);
if (!await blob.ExistsAsync())
return;
await blob.DownloadToStreamAsync(stream);
}
public async Task UploadAsync(string id, long version, string suffix, Stream stream)
{
var blobName = GetObjectName(id, version, suffix);
var blob = blobContainer.GetBlockBlobReference(blobName);
if (await blob.ExistsAsync())
{
return;
}
if (!blob.Metadata.ContainsKey(AssetVersion))
blob.Metadata.Add(AssetVersion, version.ToString());
else
blob.Metadata[AssetVersion] = version.ToString();
blob.Metadata[AssetId] = id;
await blob.UploadFromStreamAsync(stream);
await blob.SetMetadataAsync();
}
public void Connect()
{
blobContainer = azureStorageAccount.GetContainer(containerName);
}
private string GetObjectName(string id, long version, string suffix)
{
Guard.NotNullOrEmpty(id, nameof(id));
if (blobContainer == null)
{
throw new InvalidOperationException("No connection established yet.");
}
var name = $"{id}_{version}";
if (!string.IsNullOrWhiteSpace(suffix))
{
name += "_" + suffix;
}
return name;
}
}
}

2
src/Squidex.Infrastructure.AzureStorage/AzureStorageException.cs → src/Squidex.Infrastructure.Azure/Storage/AzureStorageException.cs

@ -9,7 +9,7 @@
using System;
using Microsoft.WindowsAzure.Storage;
namespace Squidex.Infrastructure.AzureStorage
namespace Squidex.Infrastructure.Azure.Storage
{
[Serializable]
public class AzureStorageException : StorageException

5
src/Squidex.Infrastructure.AzureStorage/IStorageAccountManager.cs → src/Squidex.Infrastructure.Azure/Storage/IStorageAccountManager.cs

@ -6,14 +6,17 @@
// All rights reserved.
// ==========================================================================
using System.Threading.Tasks;
using Microsoft.WindowsAzure.Storage.Blob;
namespace Squidex.Infrastructure.AzureStorage
namespace Squidex.Infrastructure.Azure.Storage
{
public interface IStorageAccountManager
{
CloudBlobClient CreateCloudBlobClient();
string GetSharedAccessSignature();
CloudBlobContainer GetContainer(string name);
}
}

9
src/Squidex.Infrastructure.AzureStorage/StorageAccountManager.cs → src/Squidex.Infrastructure.Azure/Storage/StorageAccountManager.cs

@ -7,10 +7,11 @@
// ==========================================================================
using System;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
namespace Squidex.Infrastructure.AzureStorage
namespace Squidex.Infrastructure.Azure.Storage
{
public class StorageAccountManager : IStorageAccountManager
{
@ -43,5 +44,11 @@ namespace Squidex.Infrastructure.AzureStorage
Permissions = SharedAccessAccountPermissions.Read | SharedAccessAccountPermissions.List
});
}
public CloudBlobContainer GetContainer(string name)
{
var blobClient = CreateCloudBlobClient();
return blobClient.GetContainerReference(name);
}
}
}

147
src/Squidex.Infrastructure.AzureStorage/AzureBlobAssetStore.cs

@ -1,147 +0,0 @@
// ==========================================================================
// AzureBlobAssetStore.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using Squidex.Infrastructure.Assets;
namespace Squidex.Infrastructure.AzureStorage
{
public class AzureBlobAssetStore : IAssetStore, IExternalSystem
{
private readonly IBlobContainerProvider blobContainerProvider;
private readonly string containerName;
private CloudBlobContainer blobContainer;
private const string AssetVersion = "AssetVersion";
private const string AssetId = "AssetId";
public AzureBlobAssetStore(IBlobContainerProvider blobContainerProvider, string containerName)
{
Guard.NotNullOrEmpty(containerName, nameof(containerName));
Guard.NotNull(blobContainerProvider, nameof(blobContainerProvider));
this.blobContainerProvider = blobContainerProvider;
this.containerName = containerName;
}
public async Task DownloadAsync(string id, long version, string suffix, Stream stream)
{
var blobName = GetObjectName(id, suffix);
var blob = blobContainer.GetBlockBlobReference(blobName);
if (!await blob.ExistsAsync())
return;
// look for the requested version
// first check if the original blob has the requested version
if (blob.Metadata.TryGetValue(AssetVersion, out string verionStr))
{
if (long.TryParse(verionStr, out long blobVersion))
{
// if not, then look for that snapshot which has the requested version number.
if (blobVersion != version)
{
var snapshotBlob = await FindSnapshotAsync(id, version);
blob = snapshotBlob ?? blob;
}
}
}
await blob.DownloadToStreamAsync(stream);
}
public async Task UploadAsync(string id, long version, string suffix, Stream stream)
{
var blobName = GetObjectName(id, suffix);
var blob = blobContainer.GetBlockBlobReference(blobName);
if (await blob.ExistsAsync())
{
// if it's already exist create a snapshot, and we overwrite the source blob of the snapshot.
// NOTE: not sure if there is an
await CreateVersioningSnapshotAsync(blob, id, version);
}
if (!blob.Metadata.ContainsKey(AssetVersion))
blob.Metadata.Add(AssetVersion, version.ToString());
else
blob.Metadata[AssetVersion] = version.ToString();
blob.Metadata[AssetId] = id;
await blob.UploadFromStreamAsync(stream);
await blob.SetMetadataAsync();
}
public async void Connect()
{
blobContainer = await blobContainerProvider.GetContainerAsync(containerName);
}
private string GetObjectName(string id, string suffix)
{
Guard.NotNullOrEmpty(id, nameof(id));
if (blobContainer == null)
{
throw new InvalidOperationException("No connection established yet.");
}
var name = $"{id}";
if (!string.IsNullOrWhiteSpace(suffix))
{
name += "_" + suffix;
}
return name;
}
private async Task CreateVersioningSnapshotAsync(CloudBlockBlob blob, string id, long version)
{
var metadata = new Dictionary<string, string>();
metadata.Add(AssetVersion, version.ToString());
metadata.Add(AssetId, id);
await blob.CreateSnapshotAsync(metadata,
null, null, null);
}
private async Task<CloudBlockBlob> FindSnapshotAsync(string id, long requestedVersion)
{
CloudBlockBlob resultBlob = null;
BlobContinuationToken token = null;
do
{
var listingResult = await blobContainer.ListBlobsSegmentedAsync(null, true,
BlobListingDetails.Snapshots, 10, token, null, null);
token = listingResult.ContinuationToken;
foreach (CloudBlob snapshotBlob in listingResult.Results.Cast<CloudBlob>())
{
if (snapshotBlob.Metadata.TryGetValue(AssetVersion, out string snapshotVersionStr)
&& snapshotBlob.Metadata.TryGetValue(AssetId, out string snapshotAssetId)
&& long.TryParse(snapshotVersionStr, out long snapshotVersion)
&& snapshotVersion == requestedVersion
&& snapshotAssetId == id)
{
resultBlob = snapshotBlob as CloudBlockBlob;
break;
}
}
}
while (token != null);
return resultBlob;
}
}
}

33
src/Squidex.Infrastructure.AzureStorage/BlobContainerProvider.cs

@ -1,33 +0,0 @@
// ==========================================================================
// BlobContainerProvider.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Threading.Tasks;
using Microsoft.WindowsAzure.Storage.Blob;
namespace Squidex.Infrastructure.AzureStorage
{
public class BlobContainerProvider : IBlobContainerProvider
{
private readonly IStorageAccountManager accountManager;
public BlobContainerProvider(IStorageAccountManager accountManager)
{
this.accountManager = accountManager;
}
public async Task<CloudBlobContainer> GetContainerAsync(string name)
{
var client = accountManager.CreateCloudBlobClient();
var saneName = name.Replace("@", "-").Replace(".", "-");
var container = client.GetContainerReference(saneName);
await container.CreateIfNotExistsAsync();
return container;
}
}
}

18
src/Squidex.Infrastructure.AzureStorage/IBlobContainerProvider.cs

@ -1,18 +0,0 @@
// ==========================================================================
// IBlobContainerProvider.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Threading.Tasks;
using Microsoft.WindowsAzure.Storage.Blob;
namespace Squidex.Infrastructure.AzureStorage
{
public interface IBlobContainerProvider
{
Task<CloudBlobContainer> GetContainerAsync(string name);
}
}

8
src/Squidex/Config/Domain/AssetStoreModule.cs

@ -13,7 +13,7 @@ using Squidex.Infrastructure;
using Squidex.Infrastructure.Assets;
using Squidex.Infrastructure.GoogleCloud;
using Squidex.Infrastructure.Log;
using Squidex.Infrastructure.AzureStorage;
using Squidex.Infrastructure.Azure.Storage;
// ReSharper disable InvertIf
@ -87,11 +87,7 @@ namespace Squidex.Config.Domain
.As<IStorageAccountManager>()
.SingleInstance();
builder.RegisterType<BlobContainerProvider>()
.As<IBlobContainerProvider>()
.SingleInstance();
builder.Register(c => new AzureBlobAssetStore(c.Resolve<IBlobContainerProvider>(), containerName))
builder.Register(c => new AzureBlobAssetStore(c.Resolve<IStorageAccountManager>(), containerName))
.As<IAssetStore>()
.As<IExternalSystem>()
.SingleInstance();

2
src/Squidex/Squidex.csproj

@ -29,7 +29,7 @@
<ProjectReference Include="..\Squidex.Domain.Apps.Events\Squidex.Domain.Apps.Events.csproj" />
<ProjectReference Include="..\Squidex.Domain.Users.MongoDb\Squidex.Domain.Users.MongoDb.csproj" />
<ProjectReference Include="..\Squidex.Domain.Users\Squidex.Domain.Users.csproj" />
<ProjectReference Include="..\Squidex.Infrastructure.AzureStorage\Squidex.Infrastructure.AzureStorage.csproj" />
<ProjectReference Include="..\Squidex.Infrastructure.Azure\Squidex.Infrastructure.Azure.csproj" />
<ProjectReference Include="..\Squidex.Infrastructure.GetEventStore\Squidex.Infrastructure.GetEventStore.csproj" />
<ProjectReference Include="..\Squidex.Infrastructure.GoogleCloud\Squidex.Infrastructure.GoogleCloud.csproj" />
<ProjectReference Include="..\Squidex.Infrastructure.RabbitMq\Squidex.Infrastructure.RabbitMq.csproj" />

Loading…
Cancel
Save