Skip to content

Instantly share code, notes, and snippets.

@ReubenBond
Created September 8, 2014 00:50
Show Gist options
  • Save ReubenBond/738dceb8f409afa39fe6 to your computer and use it in GitHub Desktop.
Save ReubenBond/738dceb8f409afa39fe6 to your computer and use it in GitHub Desktop.
AzureJsonStore.cs
// --------------------------------------------------------------------------------------------------------------------
// <summary>
// The Azure JSON table storage provider.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace Grains.Utilities
{
using System.Configuration;
using System.Threading.Tasks;
using FreeBay.Models.Utility;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
using Newtonsoft.Json;
using Orleans;
using Orleans.Runtime;
using Orleans.Storage;
/// <summary>
/// The Azure JSON table storage provider.
/// </summary>
public class AzureJsonStore : IStorageProvider
{
/// <summary>
/// The connection string setting.
/// </summary>
public const string ConnectionStringSetting = "ConnectionStringSetting";
/// <summary>
/// The table name setting.
/// </summary>
public const string TableNameSetting = "TableName";
/// <summary>
/// Gets or sets the log.
/// </summary>
public OrleansLogger Log { get; set; }
/// <summary>
/// Gets or sets the name.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the table.
/// </summary>
public CloudTable Table { get; set; }
/// <summary>
/// Gets or sets the account.
/// </summary>
public CloudStorageAccount Account { get; set; }
/// <summary>
/// Gets or sets the client.
/// </summary>
public CloudTableClient Client { get; set; }
/// <summary>
/// Initialization function called by Orleans Provider Manager when a new provider class instance is created
/// </summary>
/// <param name="name">Name assigned for this provider</param>
/// <param name="providerRuntime">Callback for accessing system functions in the Provider Runtime</param>
/// <param name="config">Configuration metadata to be used for this provider instance</param>
/// <returns>
/// Completion promise Task for the initialization work for this provider
/// </returns>
public async Task Init(string name, Orleans.Providers.IProviderRuntime providerRuntime, Orleans.Providers.IProviderConfiguration config)
{
var connectionStringSetting = config.Properties[ConnectionStringSetting];
if (string.IsNullOrWhiteSpace(connectionStringSetting))
{
throw new ConfigurationErrorsException(ConnectionStringSetting + " must be provided.");
}
var tableName = config.Properties[TableNameSetting];
if (string.IsNullOrWhiteSpace(tableName))
{
throw new ConfigurationErrorsException(TableNameSetting + " must be provided.");
}
var connectionString = CloudConfigurationManager.GetSetting(connectionStringSetting);
this.Account = CloudStorageAccount.Parse(connectionString);
this.Client = new CloudTableClient(this.Account.TableStorageUri, this.Account.Credentials);
this.Table = this.Client.GetTableReference(tableName);
await this.Table.CreateIfNotExistsAsync();
}
/// <summary>
/// Close function for this storage provider instance.
/// </summary>
/// <returns>
/// Completion promise for the Close operation on this provider.
/// </returns>
public Task Close()
{
return Task.FromResult(0);
}
/// <summary>
/// Read data function for this storage provider instance.
/// </summary>
/// <param name="grainType">Type of this grain [fully qualified class name]</param>
/// <param name="grainRef">Grain reference object for this grain.</param>
/// <param name="grainState">State data object to be populated for this grain.</param>
/// <returns>
/// Completion promise for the Read operation on the specified grain.
/// </returns>
public async Task ReadStateAsync(string grainType, GrainReference grainRef, IGrainState grainState)
{
var rowkey = grainState.GetType().Name;
var partitionKey = grainRef.ToKeyString();
var query = new TableQuery<GrainStateTableEntity>().Where(
TableQuery.CombineFilters(
TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, partitionKey),
TableOperators.And,
TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.Equal, rowkey)));
var result = await this.Table.ExecuteQuerySegmentedAsync(query, null);
if (result.Results != null && result.Results.Count > 0)
{
var entity = result.Results[0];
var properties = (IGrainState)JsonConvert.DeserializeObject(entity.State, grainState.GetType(), Globals.JsonConfig);
grainState.SetAll(properties.AsDictionary());
}
}
/// <summary>
/// Write data function for this storage provider instance.
/// </summary>
/// <param name="grainType">Type of this grain [fully qualified class name]</param>
/// <param name="grainRef">Grain reference object for this grain.</param>
/// <param name="grainState">State data object to be written for this grain.</param>
/// <returns>
/// Completion promise for the Write operation on the specified grain.
/// </returns>
public async Task WriteStateAsync(string grainType, GrainReference grainRef, IGrainState grainState)
{
var rowkey = grainState.GetType().Name;
var partitionKey = grainRef.ToKeyString();
var entity = new GrainStateTableEntity { PartitionKey = partitionKey, RowKey = rowkey, State = JsonConvert.SerializeObject(grainState, Globals.JsonConfig) };
await this.Table.ExecuteAsync(TableOperation.InsertOrReplace(entity));
}
/// <summary>
/// Delete / Clear data function for this storage provider instance.
/// </summary>
/// <param name="grainType">Type of this grain [fully qualified class name]</param>
/// <param name="grainRef">Grain reference object for this grain.</param>
/// <param name="grainState">Copy of last-known state data object for this grain.</param>
/// <returns>
/// Completion promise for the Delete operation on the specified grain.
/// </returns>
public async Task ClearStateAsync(string grainType, GrainReference grainRef, IGrainState grainState)
{
var rowkey = grainState.GetType().Name;
var partitionKey = grainRef.ToKeyString();
var entity = new GrainStateTableEntity { PartitionKey = partitionKey, RowKey = rowkey };
await this.Table.ExecuteAsync(TableOperation.Delete(entity));
}
/// <summary>
/// The grain state table entity.
/// </summary>
public class GrainStateTableEntity : TableEntity
{
/// <summary>
/// Gets or sets the state.
/// </summary>
public string State { get; set; }
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment