Skip to content

Commit 3abdf61

Browse files
Bump version and migrate to azure.data.tables sdk (#13)
* Migrate to Azure.Data.Tables SDK from old CosmosDB.Table SDK * Oops. Bumped Cosmos/Table version one too many. * Catch not-found exceptions. Update version in config as well. * Ensure times are UTC. * Fix Table key usage on delete.
1 parent c3c9a10 commit 3abdf61

8 files changed

+87
-111
lines changed

src/CosmosDBTableAsyncOutputCacheProvider/CacheEntity.cs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22
// Licensed under the MIT license. See the License.txt file in the project root for full license information.
33

44
namespace Microsoft.AspNet.OutputCache.CosmosDBTableAsyncOutputCacheProvider {
5-
using Microsoft.Azure.CosmosDB.Table;
6-
using Microsoft.Azure.Storage;
5+
using Azure;
6+
using Azure.Data.Tables;
77
using System;
88
using System.Collections.Generic;
99
using System.IO;
10+
using System.Runtime.Serialization;
1011
using System.Runtime.Serialization.Formatters.Binary;
1112
using System.Text;
1213

13-
class CacheEntity : TableEntity {
14+
class CacheEntity : ITableEntity {
1415
private static readonly char[] InvalidCharsInResource = { '/', '\\', '?', '#' };
1516
private const char ReplacementOfInvalidChars = '_';
1617

@@ -21,24 +22,23 @@ public CacheEntity(string cacheKey, object cacheItem, DateTime utcExpiry) {
2122
RowKey = SanitizeKey(cacheKey);
2223
PartitionKey = GeneratePartitionKey(cacheKey);
2324
CacheItem = cacheItem;
24-
UtcExpiry = utcExpiry;
25+
UtcExpiry = utcExpiry.ToUniversalTime();
2526
}
2627

28+
[IgnoreDataMember]
2729
public object CacheItem { get; set; }
28-
29-
public DateTime UtcExpiry { get; set; }
30-
31-
public override void ReadEntity(IDictionary<string, EntityProperty> properties, OperationContext operationContext) {
32-
base.ReadEntity(properties, operationContext);
33-
CacheItem = Deserialize(properties[nameof(CacheItem)].BinaryValue);
30+
[DataMember(Name = "CacheItem")]
31+
public byte[] SerializedCacheItem
32+
{
33+
get => Serialize(CacheItem);
34+
set => CacheItem = Deserialize(value);
3435
}
3536

36-
public override IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext) {
37-
var result = base.WriteEntity(operationContext);
38-
var cacheItemProperty = new EntityProperty(Serialize(CacheItem));
39-
result.Add(nameof(CacheItem), cacheItemProperty);
40-
return result;
41-
}
37+
public DateTime UtcExpiry { get; set; }
38+
public string PartitionKey { get; set; }
39+
public string RowKey { get; set; }
40+
public DateTimeOffset? Timestamp { get; set; }
41+
public ETag ETag { get; set; }
4242

4343
public static string GeneratePartitionKey(string cacheKey) {
4444
return (cacheKey.Length % 10).ToString();

src/CosmosDBTableAsyncOutputCacheProvider/CosmosDBTableOutputCacheRepository.cs

Lines changed: 52 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,22 @@ namespace Microsoft.AspNet.OutputCache.CosmosDBTableAsyncOutputCacheProvider {
55
using System;
66
using System.Collections.Specialized;
77
using System.Configuration;
8+
using System.Runtime.Caching;
89
using System.Threading.Tasks;
910
using System.Web;
10-
using Microsoft.Azure.CosmosDB.Table;
11-
using Microsoft.Azure.Storage;
11+
using Azure;
12+
using Azure.Data.Tables;
1213
using Resource;
1314

1415
class CosmosDBTableOutputCacheRepository : ITableOutputCacheRepository {
1516
private const string TableNameKey = "tableName";
1617
private const string ConnectionStringKey = "connectionStringName";
1718
private const string FixedPartitionKey = "P";
1819

19-
private CloudTable _table;
20-
private string _connectionString;
21-
private string _tableName;
22-
private object _lock = new object();
20+
private TableClient _tableClient;
21+
private readonly string _connectionString;
22+
private readonly string _tableName;
23+
private readonly object _lock = new object();
2324

2425
public CosmosDBTableOutputCacheRepository(NameValueCollection providerConfig, NameValueCollection appSettings) {
2526
var connectionStringName = providerConfig[ConnectionStringKey];
@@ -39,9 +40,7 @@ public CosmosDBTableOutputCacheRepository(NameValueCollection providerConfig, Na
3940
}
4041

4142
public object Add(string key, object entry, DateTime utcExpiry) {
42-
var retrieveOp = TableOperationHelper.Retrieve(key);
43-
var retrieveResult = _table.Execute(retrieveOp);
44-
var existingCacheEntry = retrieveResult.Result as CacheEntity;
43+
CacheEntity existingCacheEntry = Get(key) as CacheEntity;
4544

4645
if (existingCacheEntry != null && existingCacheEntry.UtcExpiry > DateTime.UtcNow) {
4746
return existingCacheEntry.CacheItem;
@@ -54,9 +53,7 @@ public object Add(string key, object entry, DateTime utcExpiry) {
5453
public async Task<object> AddAsync(string key, object entry, DateTime utcExpiry) {
5554
// If there is already a value in the cache for the specified key, the provider must return that value if not expired
5655
// and must not store the data passed by using the Add method parameters.
57-
var retrieveOp = TableOperationHelper.Retrieve(key);
58-
var retrieveResult = await _table.ExecuteAsync(retrieveOp);
59-
var existingCacheEntry = retrieveResult.Result as CacheEntity;
56+
CacheEntity existingCacheEntry = await GetAsync(key) as CacheEntity;
6057

6158
if (existingCacheEntry != null && existingCacheEntry.UtcExpiry > DateTime.UtcNow) {
6259
return existingCacheEntry.CacheItem;
@@ -67,88 +64,85 @@ public async Task<object> AddAsync(string key, object entry, DateTime utcExpiry)
6764
}
6865

6966
public object Get(string key) {
70-
var retrieveOp = TableOperationHelper.Retrieve(key);
71-
var retrieveResult = _table.Execute(retrieveOp);
72-
var existingCacheEntry = retrieveResult.Result as CacheEntity;
73-
74-
if (existingCacheEntry != null && existingCacheEntry.UtcExpiry < DateTime.UtcNow) {
75-
Remove(key);
76-
return null;
77-
} else {
78-
return existingCacheEntry?.CacheItem;
67+
try
68+
{
69+
CacheEntity existingCacheEntry = _tableClient.GetEntity<CacheEntity>(CacheEntity.GeneratePartitionKey(key), CacheEntity.SanitizeKey(key));
70+
71+
if (existingCacheEntry != null && existingCacheEntry.UtcExpiry < DateTime.UtcNow) {
72+
Remove(key);
73+
return null;
74+
} else {
75+
return existingCacheEntry?.CacheItem;
76+
}
7977
}
78+
catch (RequestFailedException rfe) when (rfe.Status == 404) { /* Entity not found */ }
79+
return null;
8080
}
8181

8282
public async Task<object> GetAsync(string key) {
83-
// Outputcache module will always first call GetAsync
84-
// so only calling EnsureTableInitializedAsync here is good enough
85-
await EnsureTableInitializedAsync();
8683

87-
var retrieveOp = TableOperationHelper.Retrieve(key);
88-
var retrieveResult = await _table.ExecuteAsync(retrieveOp);
89-
var existingCacheEntry = retrieveResult.Result as CacheEntity;
84+
try
85+
{
86+
// Outputcache module will always first call GetAsync
87+
// so only calling EnsureTableInitializedAsync here is good enough
88+
await EnsureTableInitializedAsync();
9089

91-
if (existingCacheEntry != null && existingCacheEntry.UtcExpiry < DateTime.UtcNow) {
92-
await RemoveAsync(key);
93-
return null;
94-
} else {
95-
return existingCacheEntry?.CacheItem;
90+
CacheEntity existingCacheEntry = await _tableClient.GetEntityAsync<CacheEntity>(CacheEntity.GeneratePartitionKey(key), CacheEntity.SanitizeKey(key));
91+
92+
if (existingCacheEntry != null && existingCacheEntry.UtcExpiry < DateTime.UtcNow) {
93+
await RemoveAsync(key);
94+
return null;
95+
} else {
96+
return existingCacheEntry?.CacheItem;
97+
}
9698
}
99+
catch (RequestFailedException rfe) when (rfe.Status == 404) { /* Entity not found */ }
100+
return null;
97101
}
98102

99103
public void Remove(string key) {
100-
var removeOp = TableOperationHelper.Delete(key);
101-
_table.Execute(removeOp);
104+
_tableClient.DeleteEntity(CacheEntity.GeneratePartitionKey(key), CacheEntity.SanitizeKey(key), ETag.All);
102105
}
103106

104107
public async Task RemoveAsync(string key) {
105-
var removeOp = TableOperationHelper.Delete(key);
106-
await _table.ExecuteAsync(removeOp);
108+
await _tableClient.DeleteEntityAsync(CacheEntity.GeneratePartitionKey(key), CacheEntity.SanitizeKey(key), ETag.All);
107109
}
108110

109111
public void Set(string key, object entry, DateTime utcExpiry) {
110-
var insertOp = TableOperationHelper.InsertOrReplace(key, entry, utcExpiry);
111-
_table.Execute(insertOp);
112+
_tableClient.UpsertEntity<CacheEntity>(new CacheEntity(key, entry, utcExpiry));
112113
}
113114

114115
public async Task SetAsync(string key, object entry, DateTime utcExpiry) {
115116
//Check if the key is already in database
116117
//If there is already a value in the cache for the specified key, the Set method will update it.
117118
//Otherwise it will insert the entry.
118-
var insertOp = TableOperationHelper.InsertOrReplace(key, entry, utcExpiry);
119-
await _table.ExecuteAsync(insertOp);
119+
await _tableClient.UpsertEntityAsync<CacheEntity>(new CacheEntity(key, entry, utcExpiry));
120120
}
121121

122122
private async Task EnsureTableInitializedAsync() {
123-
if (_table != null) {
123+
if (_tableClient != null) {
124124
return;
125125
}
126126

127127
try {
128128
lock (_lock) {
129-
if (_table != null) {
129+
if (_tableClient != null) {
130130
return;
131131
}
132132

133-
var storageAccount = CreateStorageAccount();
134-
var tableClient = storageAccount.CreateCloudTableClient();
135-
_table = tableClient.GetTableReference(_tableName);
133+
try {
134+
_tableClient = new TableClient(_connectionString, _tableName);
135+
} catch (FormatException) {
136+
throw new HttpException(SR.Invalid_storage_account_information);
137+
} catch (ArgumentException) {
138+
throw new HttpException(SR.Invalid_storage_account_information);
139+
}
136140
}
137141

138-
// The sync version API causes deadlock when using CosmosDB table.
139-
await _table.CreateIfNotExistsAsync();
140-
} catch (StorageException ex) {
141-
throw new HttpException(SR.Fail_to_create_table, ex);
142-
}
143-
}
142+
await _tableClient.CreateIfNotExistsAsync();
144143

145-
private CloudStorageAccount CreateStorageAccount() {
146-
try {
147-
return CloudStorageAccount.Parse(_connectionString);
148-
} catch (FormatException) {
149-
throw new HttpException(SR.Invalid_storage_account_information);
150-
} catch (ArgumentException) {
151-
throw new HttpException(SR.Invalid_storage_account_information);
144+
} catch (RequestFailedException ex) {
145+
throw new HttpException(SR.Fail_to_create_table, ex);
152146
}
153147
}
154148
}

src/CosmosDBTableAsyncOutputCacheProvider/Microsoft.AspNet.OutputCache.CosmosDBTableAsyncOutputCacheProvider.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
<Reference Include="System.Configuration" />
5050
<Reference Include="System.Core" />
5151
<Reference Include="System.Runtime.Caching" />
52+
<Reference Include="System.Runtime.Serialization" />
5253
<Reference Include="System.Web" />
5354
<Reference Include="System.Xml.Linq" />
5455
<Reference Include="System.Data.DataSetExtensions" />
@@ -74,11 +75,10 @@
7475
<DesignTime>True</DesignTime>
7576
<DependentUpon>SR.resx</DependentUpon>
7677
</Compile>
77-
<Compile Include="TableOperationHelper.cs" />
7878
</ItemGroup>
7979
<ItemGroup>
80-
<PackageReference Include="Microsoft.Azure.CosmosDB.Table">
81-
<Version>1.1.0</Version>
80+
<PackageReference Include="Azure.Data.Tables">
81+
<Version>12.2.0</Version>
8282
</PackageReference>
8383
</ItemGroup>
8484
<ItemGroup>

src/CosmosDBTableAsyncOutputCacheProvider/TableOperationHelper.cs

Lines changed: 0 additions & 26 deletions
This file was deleted.

src/packages/CosmosDBTableAsyncOutputCacheProvider.nupkg/Microsoft.AspNet.OutputCache.CosmosDBTableAsyncOutputCacheProvider.nuspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<copyright>&#169; Microsoft Corporation. All rights reserved.</copyright>
99
<dependencies>
1010
<dependency id="Microsoft.AspNet.OutputCache.OutputCacheModuleAsync" version="$OutputCacheModuleAsyncNuGetPackageVersion$" />
11-
<dependency id="Microsoft.Azure.CosmosDB.Table" version="$CosmosDBTableNuGetPackageVersion$" />
11+
<dependency id="Azure.Data.Tables" version="$AzureTablesNuGetPackageVersion$" />
1212
</dependencies>
1313
<title>Microsoft ASP.NET CosmosDB Table Async OutputCache Provider</title>
1414
<description>In .Net 4.6.2, asp.net enables developer plug in async version of OutputCache module which is a good fit for the non-in-memory OutputCache data store. This OutputCache provider can use both CosmosDB(table model) and Azure storage table as the data store and leverages async operation to provide better scability.</description>

src/packages/CosmosDBTableAsyncOutputCacheProvider.nupkg/content/Net462/web.config.install.xdt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
of SQL Server which you will use as the data store.
2222
-->
2323
<add name="CosmosDBTableAsyncOutputCacheProvider" connectionStringName="StorageConnectionStringForOutputCacheProvider" tableName="[TableName]"
24-
type="Microsoft.AspNet.OutputCache.CosmosDBTableAsyncOutputCacheProvider.CosmosDBTableAsyncOutputCacheProvider, Microsoft.AspNet.OutputCache.CosmosDBTableAsyncOutputCacheProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
24+
type="Microsoft.AspNet.OutputCache.CosmosDBTableAsyncOutputCacheProvider.CosmosDBTableAsyncOutputCacheProvider, Microsoft.AspNet.OutputCache.CosmosDBTableAsyncOutputCacheProvider, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
2525
xdt:Transform="InsertIfMissing"/>
2626
</providers>
2727
</outputCache>

src/packages/Packages.csproj

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,21 @@
2424
</PropertyGroup>
2525
<ItemGroup>
2626
<NuGetProject Include="OutputCacheModuleAsync.nupkg\Microsoft.AspNet.OutputCache.OutputCacheModuleAsync.nuproj" />
27+
<None Include="OutputCacheModuleAsync.nupkg\Microsoft.AspNet.OutputCache.OutputCacheModuleAsync.nuspec" />
28+
<None Include="OutputCacheModuleAsync.nupkg\content\Net462\web.config.install.xdt" />
29+
<None Include="OutputCacheModuleAsync.nupkg\content\Net462\web.config.uninstall.xdt" />
30+
</ItemGroup>
31+
<ItemGroup>
2732
<NuGetProject Include="SQLAsyncOutputCacheProvider.nupkg\Microsoft.AspNet.OutputCache.SQLAsyncOutputCacheProvider.nuproj" />
28-
<NuGetProject Include="CosmosDBTableAsyncOutputCacheProvider.nupkg\Microsoft.AspNet.OutputCache.CosmosDBTableAsyncOutputCacheProvider.nuproj" />
33+
<None Include="SQLAsyncOutputCacheProvider.nupkg\Microsoft.AspNet.OutputCache.SQLAsyncOutputCacheProvider.nuspec" />
34+
<None Include="SQLAsyncOutputCacheProvider.nupkg\content\Net462\web.config.install.xdt" />
35+
<None Include="SQLAsyncOutputCacheProvider.nupkg\content\Net462\web.config.uninstall.xdt" />
2936
</ItemGroup>
3037
<ItemGroup>
38+
<NuGetProject Include="CosmosDBTableAsyncOutputCacheProvider.nupkg\Microsoft.AspNet.OutputCache.CosmosDBTableAsyncOutputCacheProvider.nuproj" />
3139
<None Include="CosmosDBTableAsyncOutputCacheProvider.nupkg\Microsoft.AspNet.OutputCache.CosmosDBTableAsyncOutputCacheProvider.nuspec" />
32-
<None Include="OutputCacheModuleAsync.nupkg\Microsoft.AspNet.OutputCache.OutputCacheModuleAsync.nuspec" />
33-
<None Include="SQLAsyncOutputCacheProvider.nupkg\Microsoft.AspNet.OutputCache.SQLAsyncOutputCacheProvider.nuspec" />
40+
<None Include="CosmosDBTableAsyncOutputCacheProvider.nupkg\content\Net462\web.config.install.xdt" />
41+
<None Include="CosmosDBTableAsyncOutputCacheProvider.nupkg\content\Net462\web.config.uninstall.xdt" />
3442
</ItemGroup>
3543
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
3644
<Target Name="Build">

tools/CosmosDBTableAsyncOutputCacheProvider.settings.targets

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,20 @@
44
<PropertyGroup>
55
<BuildQuality Condition="'$(BuildQuality)' == ''">rtm</BuildQuality>
66
<VersionMajor>1</VersionMajor>
7-
<VersionMinor>0</VersionMinor>
7+
<VersionMinor>1</VersionMinor>
88
<VersionRelease>0</VersionRelease>
99
</PropertyGroup>
1010
<PropertyGroup Label="NuGet package dependencies">
1111
<OutputCacheModuleAsyncNuGetPackageVersion>1.0.2</OutputCacheModuleAsyncNuGetPackageVersion>
12-
<CosmosDBTableNuGetPackageVersion>1.1.0</CosmosDBTableNuGetPackageVersion>
12+
<AzureTablesNuGetPackageVersion>12.2.0</AzureTablesNuGetPackageVersion>
1313
</PropertyGroup>
1414
<Target Name="SetNuSpecProperties">
1515
<PropertyGroup>
1616
<NuSpecProperties>
1717
NuGetPackageVersion=$(NuGetPackageVersion);
1818
NuGetPackageId=$(NuGetPackageId);
1919
OutputCacheModuleAsyncNuGetPackageVersion=$(OutputCacheModuleAsyncNuGetPackageVersion);
20-
CosmosDBTableNuGetPackageVersion=$(CosmosDBTableNuGetPackageVersion);
20+
AzureTablesNuGetPackageVersion=$(AzureTablesNuGetPackageVersion);
2121
</NuSpecProperties>
2222
</PropertyGroup>
2323
</Target>

0 commit comments

Comments
 (0)