зеркало из https://github.com/dotnet/orleans.git
Improve serialization of GrainReference when using JSON (#3073)
This commit is contained in:
Родитель
d97e91adbd
Коммит
6dafe25a5c
|
@ -287,49 +287,61 @@ namespace Orleans.Serialization
|
|||
|
||||
internal class GrainReferenceConverter : JsonConverter
|
||||
{
|
||||
private static readonly Type GrainReferenceType;
|
||||
|
||||
private static readonly ConcurrentDictionary<Type, GrainFactory.GrainReferenceCaster> Casters =
|
||||
new ConcurrentDictionary<Type, GrainFactory.GrainReferenceCaster>();
|
||||
private static readonly Func<Type, GrainFactory.GrainReferenceCaster> CreateCasterDelegate = CreateCaster;
|
||||
private static readonly Type AddressableType = typeof(IAddressable);
|
||||
private readonly IGrainFactory grainFactory;
|
||||
private readonly JsonSerializer internalSerializer;
|
||||
|
||||
public GrainReferenceConverter(IGrainFactory grainFactory)
|
||||
{
|
||||
this.grainFactory = grainFactory;
|
||||
}
|
||||
|
||||
static GrainReferenceConverter()
|
||||
{
|
||||
GrainReferenceType = typeof(GrainReference);
|
||||
// Create a serializer for internal serialization which does not have a specified GrainReference serializer.
|
||||
// This internal serializer will use GrainReference's ISerializable implementation for serialization and deserialization.
|
||||
this.internalSerializer = JsonSerializer.Create(new JsonSerializerSettings
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.All,
|
||||
PreserveReferencesHandling = PreserveReferencesHandling.None,
|
||||
DateFormatHandling = DateFormatHandling.IsoDateFormat,
|
||||
DefaultValueHandling = DefaultValueHandling.Ignore,
|
||||
MissingMemberHandling = MissingMemberHandling.Ignore,
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
|
||||
Formatting = Formatting.None,
|
||||
Converters =
|
||||
{
|
||||
new IPAddressConverter(),
|
||||
new IPEndPointConverter(),
|
||||
new GrainIdConverter(),
|
||||
new SiloAddressConverter(),
|
||||
new UniqueKeyConverter()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return GrainReferenceType.IsAssignableFrom(objectType);
|
||||
return AddressableType.IsAssignableFrom(objectType);
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
var key = (value as GrainReference)?.ToKeyString();
|
||||
serializer.Serialize(writer, key);
|
||||
// Serialize the grain reference using the internal serializer.
|
||||
this.internalSerializer.Serialize(writer, value);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var key = serializer.Deserialize<string>(reader);
|
||||
if (string.IsNullOrWhiteSpace(key)) return null;
|
||||
// Deserialize using the internal serializer which will use the concrete GrainReference implementation's
|
||||
// ISerializable constructor.
|
||||
var result = this.internalSerializer.Deserialize(reader, objectType);
|
||||
var grainRef = result as IAddressable;
|
||||
if (grainRef == null) return result;
|
||||
|
||||
var result = GrainReference.FromKeyString(key, null);
|
||||
this.grainFactory.BindGrainReference(result);
|
||||
return Casters.GetOrAdd(objectType, CreateCasterDelegate)(result);
|
||||
}
|
||||
|
||||
private static GrainFactory.GrainReferenceCaster CreateCaster(Type grainReferenceType)
|
||||
{
|
||||
var interfaceType = grainReferenceType.GetTypeInfo().GetCustomAttribute<GrainReferenceAttribute>().TargetType;
|
||||
return GrainCasterFactory.CreateGrainReferenceCaster(interfaceType, grainReferenceType);
|
||||
// Bind the deserialized grain reference to the runtime.
|
||||
this.grainFactory.BindGrainReference(grainRef);
|
||||
return grainRef;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ using System.IO;
|
|||
using System.Runtime.Serialization;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Orleans;
|
||||
using Orleans.Runtime;
|
||||
using Orleans.Serialization;
|
||||
|
@ -101,6 +102,33 @@ namespace DefaultCluster.Tests.General
|
|||
TestGrainReferenceSerialization(id, true, true);
|
||||
}
|
||||
|
||||
[Fact, TestCategory("Serialization"), TestCategory("JSON")]
|
||||
public async Task GrainReference_Json_Serialization_Nested()
|
||||
{
|
||||
var settings = OrleansJsonSerializer.GetDefaultSerializerSettings(HostedCluster.SerializationManager, HostedCluster.GrainFactory);
|
||||
|
||||
var grain = HostedCluster.GrainFactory.GetGrain<ISimpleGrain>(GetRandomGrainId());
|
||||
await grain.SetA(56820);
|
||||
var input = new GenericGrainReferenceHolder
|
||||
{
|
||||
Reference = grain as GrainReference
|
||||
};
|
||||
|
||||
var json = JsonConvert.SerializeObject(input, settings);
|
||||
var output = JsonConvert.DeserializeObject<GenericGrainReferenceHolder>(json, settings);
|
||||
|
||||
Assert.Equal(input.Reference, output.Reference);
|
||||
var reference = output.Reference;
|
||||
Assert.Equal(56820, await ((ISimpleGrain)reference).GetA());
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class GenericGrainReferenceHolder
|
||||
{
|
||||
[JsonProperty]
|
||||
public GrainReference Reference { get; set; }
|
||||
}
|
||||
|
||||
[Fact, TestCategory("Serialization"), TestCategory("JSON")]
|
||||
public void GrainReference_Json_Serialization_Unresolved()
|
||||
{
|
||||
|
@ -219,13 +247,8 @@ namespace DefaultCluster.Tests.General
|
|||
{
|
||||
var settings = OrleansJsonSerializer.GetDefaultSerializerSettings(this.HostedCluster.SerializationManager, this.GrainFactory);
|
||||
// http://james.newtonking.com/json/help/index.html?topic=html/T_Newtonsoft_Json_JsonConvert.htm
|
||||
string json = Newtonsoft.Json.JsonConvert.SerializeObject(obj, settings);
|
||||
object other = Newtonsoft.Json.JsonConvert.DeserializeObject(json, obj.GetType(), settings);
|
||||
#if NETSTANDARD_TODO
|
||||
// On .NET Standard, currently we need to manually fixup grain references.
|
||||
var otherAsRef = other as Orleans.Runtime.GrainReference;
|
||||
if (otherAsRef != null) this.GrainFactory.BindGrainReference(otherAsRef);
|
||||
#endif
|
||||
string json = JsonConvert.SerializeObject(obj, settings);
|
||||
object other = JsonConvert.DeserializeObject(json, typeof(T), settings);
|
||||
return (T)other;
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче