Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Commit

Permalink
Merge pull request #19 from ilmax/feat/update-package
Browse files Browse the repository at this point in the history
feat: Use the new Azure.Storage.Blobs package
  • Loading branch information
0x414c49 authored Aug 25, 2022
2 parents 0193f29 + 4ff2bbb commit a10dcb2
Show file tree
Hide file tree
Showing 12 changed files with 140 additions and 75 deletions.
1 change: 1 addition & 0 deletions AutoNumber.sln
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7E1BB869-9152-48ED-9D43-D846800D7DBF}"
ProjectSection(SolutionItems) = preProject
.github\workflows\dotnet.yml = .github\workflows\dotnet.yml
README.md = README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests", "UnitTests\UnitTests.csproj", "{2D578C72-24A1-4EE0-A5E8-30D76FC297B8}"
Expand Down
16 changes: 10 additions & 6 deletions AutoNumber/AutoNumber.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
<AssemblyTitle>SnowMaker</AssemblyTitle>
<Product>AzureAutoNumber</Product>
<Description>High performance, distributed unique id generator for Azure environments.</Description>
<Version>1.3.3</Version>
<AssemblyVersion>1.3.3.0</AssemblyVersion>
<FileVersion>1.3.3.0</FileVersion>
<Version>1.4.0</Version>
<AssemblyVersion>1.4.0.0</AssemblyVersion>
<FileVersion>1.4.0.0</FileVersion>
<OutputPath>bin\$(Configuration)\</OutputPath>
<Authors>Ali Bahraminezhad</Authors>
<PackageLicenseExpression>MS-PL</PackageLicenseExpression>
Expand All @@ -18,9 +18,13 @@
<AssemblyName>AutoNumber</AssemblyName>
<RootNamespace>AutoNumber</RootNamespace>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageReleaseNotes>Upgrade packages and add support for .NET6</PackageReleaseNotes>
<PackageReleaseNotes>- Use "Azure.Storage.Blobs" instead of deprecated package of WindowsAzure.Storage

**Breaking changes:**
Method "UseStorageAccount(CloudStorageAccount storageAccount) removed and a new method
UseBlobServiceClient(BlobServiceClient blobServiceClient) added.</PackageReleaseNotes>
<PackageId>AzureAutoNumber</PackageId>
<PackageVersion>1.3.3</PackageVersion>
<PackageVersion>1.4.0</PackageVersion>
<SignAssembly>False</SignAssembly>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
Expand All @@ -30,11 +34,11 @@
<DebugType>pdbonly</DebugType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Storage.Blobs" Version="12.13.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
<PackageReference Include="WindowsAzure.Storage" Version="9.3.3" />
</ItemGroup>
</Project>
118 changes: 87 additions & 31 deletions AutoNumber/BlobOptimisticDataStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,41 @@
using AutoNumber.Extensions;
using AutoNumber.Interfaces;
using AutoNumber.Options;
using Azure;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Azure.Storage.Blobs.Specialized;
using Microsoft.Extensions.Options;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;

namespace AutoNumber
{
public class BlobOptimisticDataStore : IOptimisticDataStore
{
private const string SeedValue = "1";
private readonly CloudBlobContainer blobContainer;
private readonly ConcurrentDictionary<string, ICloudBlob> blobReferences;
private readonly BlobContainerClient blobContainer;
private readonly ConcurrentDictionary<string, BlockBlobClient> blobReferences;
private readonly object blobReferencesLock = new object();

public BlobOptimisticDataStore(CloudStorageAccount account, string containerName)
public BlobOptimisticDataStore(BlobServiceClient blobServiceClient, string containerName)
{
var blobClient = account.CreateCloudBlobClient();
blobContainer = blobClient.GetContainerReference(containerName.ToLower());
blobReferences = new ConcurrentDictionary<string, ICloudBlob>();
blobContainer = blobServiceClient.GetBlobContainerClient(containerName.ToLower());
blobReferences = new ConcurrentDictionary<string, BlockBlobClient>();
}

public BlobOptimisticDataStore(CloudStorageAccount cloudStorageAccount, IOptions<AutoNumberOptions> options)
: this(cloudStorageAccount, options.Value.StorageContainerName)
public BlobOptimisticDataStore(BlobServiceClient blobServiceClient, IOptions<AutoNumberOptions> options)
: this(blobServiceClient, options.Value.StorageContainerName)
{
}

public string GetData(string blockName)
{
return GetDataAsync(blockName).GetAwaiter().GetResult();
var blobReference = GetBlobReference(blockName);

using (var stream = new MemoryStream())
{
blobReference.DownloadTo(stream);
return Encoding.UTF8.GetString(stream.ToArray());
}
}

public async Task<string> GetDataAsync(string blockName)
Expand All @@ -42,34 +49,65 @@ public async Task<string> GetDataAsync(string blockName)

using (var stream = new MemoryStream())
{
await blobReference.DownloadToStreamAsync(stream).ConfigureAwait(false);
await blobReference.DownloadToAsync(stream).ConfigureAwait(false);
return Encoding.UTF8.GetString(stream.ToArray());
}
}

public async Task<bool> Init()
public async Task<bool> InitAsync()
{
var result = await blobContainer.CreateIfNotExistsAsync().ConfigureAwait(false);
return result == null || result.Value != null;
}

public bool Init()
{
return await blobContainer.CreateIfNotExistsAsync().ConfigureAwait(false);
var result = blobContainer.CreateIfNotExists();
return result == null || result.Value != null;
}

public bool TryOptimisticWrite(string blockName, string data)
{
return TryOptimisticWriteAsync(blockName, data).GetAwaiter().GetResult();
var blobReference = GetBlobReference(blockName);
try
{
var blobRequestCondition = new BlobRequestConditions
{
IfMatch = (blobReference.GetProperties()).Value.ETag
};
UploadText(
blobReference,
data,
blobRequestCondition);
}
catch (RequestFailedException exc)
{
if (exc.Status == (int)HttpStatusCode.PreconditionFailed)
return false;

throw;
}

return true;
}

public async Task<bool> TryOptimisticWriteAsync(string blockName, string data)
{
var blobReference = GetBlobReference(blockName);
try
{
var blobRequestCondition = new BlobRequestConditions
{
IfMatch = (await blobReference.GetPropertiesAsync()).Value.ETag
};
await UploadTextAsync(
blobReference,
data,
AccessCondition.GenerateIfMatchCondition(blobReference.Properties.ETag)).ConfigureAwait(false);
blobRequestCondition).ConfigureAwait(false);
}
catch (StorageException exc)
catch (RequestFailedException exc)
{
if (exc.RequestInformation.HttpStatusCode == (int) HttpStatusCode.PreconditionFailed)
if (exc.Status == (int)HttpStatusCode.PreconditionFailed)
return false;

throw;
Expand All @@ -78,43 +116,61 @@ await UploadTextAsync(
return true;
}

private ICloudBlob GetBlobReference(string blockName)
private BlockBlobClient GetBlobReference(string blockName)
{
return blobReferences.GetValue(
blockName,
blobReferencesLock,
() => InitializeBlobReferenceAsync(blockName).GetAwaiter().GetResult());
() => InitializeBlobReference(blockName));
}

private async Task<ICloudBlob> InitializeBlobReferenceAsync(string blockName)
private BlockBlobClient InitializeBlobReference(string blockName)
{
var blobReference = blobContainer.GetBlockBlobReference(blockName);
var blobReference = blobContainer.GetBlockBlobClient(blockName);

if (await blobReference.ExistsAsync().ConfigureAwait(false))
if (blobReference.Exists())
return blobReference;

try
{
await UploadTextAsync(blobReference, SeedValue, AccessCondition.GenerateIfNoneMatchCondition("*"))
.ConfigureAwait(false);
var blobRequestCondition = new BlobRequestConditions
{
IfNoneMatch = ETag.All
};
UploadText(blobReference, SeedValue, blobRequestCondition);
}
catch (StorageException uploadException)
catch (RequestFailedException uploadException)
{
if (uploadException.RequestInformation.HttpStatusCode != (int) HttpStatusCode.Conflict)
if (uploadException.Status != (int)HttpStatusCode.Conflict)
throw;
}

return blobReference;
}

private async Task UploadTextAsync(ICloudBlob blob, string text, AccessCondition accessCondition)
private async Task UploadTextAsync(BlockBlobClient blob, string text, BlobRequestConditions accessCondition)
{
blob.Properties.ContentType = "utf-8";
blob.Properties.ContentType = "text/plain";
var header = new BlobHttpHeaders
{
ContentType = "text/plain"
};

using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(text)))
{
await blob.UploadAsync(stream, header, null, accessCondition, null, null).ConfigureAwait(false);
}
}

private void UploadText(BlockBlobClient blob, string text, BlobRequestConditions accessCondition)
{
var header = new BlobHttpHeaders
{
ContentType = "text/plain"
};

using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(text)))
{
await blob.UploadFromStreamAsync(stream, accessCondition, null, null).ConfigureAwait(false);
blob.Upload(stream, header, null, accessCondition, null, null);
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion AutoNumber/DebugOnlyFileDataStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,16 @@ public Task<string> GetDataAsync(string blockName)
throw new NotImplementedException();
}

public Task<bool> Init()
public Task<bool> InitAsync()
{
return Task.FromResult(true);
}

public bool Init()
{
return true;
}

public bool TryOptimisticWrite(string blockName, string data)
{
var blockPath = Path.Combine(directoryPath, $"{blockName}.txt");
Expand Down
14 changes: 7 additions & 7 deletions AutoNumber/Extensions/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using System;
using AutoNumber.Interfaces;
using AutoNumber.Options;
using Azure.Storage.Blobs;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.WindowsAzure.Storage;

namespace AutoNumber
{
Expand Down Expand Up @@ -35,16 +35,16 @@ public static IServiceCollection AddAutoNumber(this IServiceCollection services,

services.AddSingleton<IOptimisticDataStore, BlobOptimisticDataStore>(x =>
{
CloudStorageAccount storageAccount = null;
BlobServiceClient blobServiceClient = null;
if (options.CloudStorageAccount != null)
storageAccount = options.CloudStorageAccount;
if (options.BlobServiceClient != null)
blobServiceClient = options.BlobServiceClient;
else if (options.StorageAccountConnectionString == null)
storageAccount = x.GetService<CloudStorageAccount>();
blobServiceClient = x.GetService<BlobServiceClient>();
else
storageAccount = CloudStorageAccount.Parse(options.StorageAccountConnectionString);
blobServiceClient = new BlobServiceClient(options.StorageAccountConnectionString);
return new BlobOptimisticDataStore(storageAccount, options.StorageContainerName);
return new BlobOptimisticDataStore(blobServiceClient, options.StorageContainerName);
});

services.AddSingleton<IUniqueIdGenerator, UniqueIdGenerator>(x
Expand Down
3 changes: 2 additions & 1 deletion AutoNumber/Interfaces/IOptimisticDataStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public interface IOptimisticDataStore
Task<string> GetDataAsync(string blockName);
bool TryOptimisticWrite(string blockName, string data);
Task<bool> TryOptimisticWriteAsync(string blockName, string data);
Task<bool> Init();
Task<bool> InitAsync();
bool Init();
}
}
4 changes: 2 additions & 2 deletions AutoNumber/Options/AutoNumberOptions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Microsoft.WindowsAzure.Storage;
using Azure.Storage.Blobs;

namespace AutoNumber.Options
{
Expand All @@ -8,6 +8,6 @@ public class AutoNumberOptions
public int MaxWriteAttempts { get; set; } = 100;
public string StorageContainerName { get; set; } = "unique-urls";
public string StorageAccountConnectionString { get; set; }
public CloudStorageAccount CloudStorageAccount { get; set; }
public BlobServiceClient BlobServiceClient { get; set; }
}
}
8 changes: 4 additions & 4 deletions AutoNumber/Options/AutoNumberOptionsBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;
using Azure.Storage.Blobs;
using Microsoft.Extensions.Configuration;
using Microsoft.WindowsAzure.Storage;

namespace AutoNumber.Options
{
Expand Down Expand Up @@ -42,10 +42,10 @@ public AutoNumberOptionsBuilder UseStorageAccount(string connectionStringOrName)
return this;
}

public AutoNumberOptionsBuilder UseStorageAccount(CloudStorageAccount storageAccount)
public AutoNumberOptionsBuilder UseBlobServiceClient(BlobServiceClient blobServiceClient)
{
Options.CloudStorageAccount = storageAccount
?? throw new ArgumentNullException(nameof(storageAccount));
Options.BlobServiceClient = blobServiceClient
?? throw new ArgumentNullException(nameof(blobServiceClient));

return this;
}
Expand Down
4 changes: 1 addition & 3 deletions AutoNumber/UniqueIdGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,7 @@ public int MaxWriteAttempts
public UniqueIdGenerator(IOptimisticDataStore optimisticDataStore)
{
this.optimisticDataStore = optimisticDataStore;
optimisticDataStore.Init()
.GetAwaiter()
.GetResult();
optimisticDataStore.Init();
}

public UniqueIdGenerator(IOptimisticDataStore optimisticDataStore, IOptions<AutoNumberOptions> options)
Expand Down
Loading

0 comments on commit a10dcb2

Please sign in to comment.