Skip to content

Instantly share code, notes, and snippets.

@rikbosch
Created April 26, 2019 08:29
Show Gist options
  • Save rikbosch/4afc5f7bb00bfab3d02c5995516efc70 to your computer and use it in GitHub Desktop.
Save rikbosch/4afc5f7bb00bfab3d02c5995516efc70 to your computer and use it in GitHub Desktop.
AdoNetJsonStorageProvider for Orleans, allowing custom jsonserializer settings
using System;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Orleans;
using Orleans.Providers;
using Orleans.Runtime;
using Orleans.Serialization;
using Orleans.Storage;
namespace Ao.Shared.Grains.StorageProviders
{
public class PrivateSetterCamelCasePropertyNamesContractResolver : CamelCasePropertyNamesContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var jProperty = base.CreateProperty(member, memberSerialization);
if (jProperty.Writable)
return jProperty;
jProperty.Writable = IsPropertyWithSetter(member);
return jProperty;
}
static bool IsPropertyWithSetter(MemberInfo member)
{
var property = member as PropertyInfo;
return property?.GetSetMethod(true) != null;
}
}
/// <summary>
/// Custom storage provider which wraps AdoNetStorageProvider
/// Allowing custom json serializer settings
/// </summary>
public class AdoNetJsonStorageProvider : IStorageProvider
{
private readonly AdoNetStorageProvider _inner;
public AdoNetJsonStorageProvider(AdoNetStorageProvider inner)
{
_inner = inner ?? throw new ArgumentNullException(nameof(inner));
}
public Logger Log => _inner.Log;
public string Name => _inner.Name;
public Task ClearStateAsync(string grainType, GrainReference grainReference, IGrainState grainState) => _inner.ClearStateAsync(grainType, grainReference, grainState);
public Task Close() => _inner.Close();
public async Task Init(string name, IProviderRuntime providerRuntime, IProviderConfiguration config)
{
await _inner.Init(name, providerRuntime, config);
// replace serialization picker with custom one
// and implement IStorageDeserializer with private setter support
// this is how orleans currently configures the json serializer settings for storage
var serializationManager = providerRuntime.ServiceProvider.GetService<SerializationManager>();
var jsonSerializerSettings = OrleansJsonSerializer.UpdateSerializerSettings(OrleansJsonSerializer.GetDefaultSerializerSettings(serializationManager, providerRuntime.GrainFactory), config);
var jsonDeserializerSettings = OrleansJsonSerializer.UpdateSerializerSettings(OrleansJsonSerializer.GetDefaultSerializerSettings(serializationManager, providerRuntime.GrainFactory), config);
// we want to use a custom contractresolver
// when deserializing
jsonDeserializerSettings.ContractResolver = new PrivateSetterCamelCasePropertyNamesContractResolver();
_inner.StorageSerializationPicker = new DefaultRelationalStoragePicker(
new[] { new OrleansStorageDefaultJsonDeserializer(jsonDeserializerSettings, null) },
new[] { new OrleansStorageDefaultJsonSerializer(jsonSerializerSettings, null) }
);
}
public Task ReadStateAsync(string grainType, GrainReference grainReference, IGrainState grainState) => _inner.ReadStateAsync(grainType, grainReference, grainState);
public Task WriteStateAsync(string grainType, GrainReference grainReference, IGrainState grainState) => _inner.WriteStateAsync(grainType, grainReference, grainState);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment