Browse Source

Json simplified

pull/169/head
Sebastian Stehle 9 years ago
parent
commit
4566066443
  1. 6
      src/Squidex.Domain.Apps.Read/State/Orleans/AppStateEventConsumer.cs
  2. 16
      src/Squidex.Domain.Apps.Read/State/Orleans/Grains/IAppStateGrain.cs
  3. 28
      src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/AppStateGrain.cs
  4. 17
      src/Squidex.Infrastructure/Json/Orleans/IJsonValue.cs
  5. 57
      src/Squidex.Infrastructure/Json/Orleans/J.cs
  6. 18
      src/Squidex.Infrastructure/Json/Orleans/JExtensions.cs
  7. 21
      src/Squidex.Infrastructure/Json/Orleans/JsonExternalSerializer.cs
  8. 4
      src/Squidex/Config/Orleans/CustomJsonSerializer.cs
  9. 55
      tests/Squidex.Infrastructure.Tests/Json/Orleans/JsonExternalSerializerTests.cs

6
src/Squidex.Domain.Apps.Read/State/Orleans/AppStateEventConsumer.cs

@ -1,5 +1,5 @@
// ==========================================================================
// StateEventConsumer.cs
// AppStateEventConsumer.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
@ -8,12 +8,12 @@
using System.Threading.Tasks;
using Orleans;
using Orleans.Concurrency;
using Squidex.Domain.Apps.Events;
using Squidex.Domain.Apps.Events.Apps;
using Squidex.Domain.Apps.Read.State.Orleans.Grains;
using Squidex.Infrastructure;
using Squidex.Infrastructure.CQRS.Events;
using Squidex.Infrastructure.Json.Orleans;
using Squidex.Infrastructure.Tasks;
namespace Squidex.Domain.Apps.Read.State.Orleans
@ -50,7 +50,7 @@ namespace Squidex.Domain.Apps.Read.State.Orleans
{
var appGrain = factory.GetGrain<IAppStateGrain>(appEvent.AppId.Name);
await appGrain.HandleAsync(new Immutable<Envelope<IEvent>>(@event));
await appGrain.HandleAsync(@event.AsJ());
}
if (@event.Payload is AppContributorAssigned contributorAssigned)

16
src/Squidex.Domain.Apps.Read/State/Orleans/Grains/IAppStateGrain.cs

@ -10,28 +10,28 @@ using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Orleans;
using Orleans.Concurrency;
using Squidex.Domain.Apps.Read.Apps;
using Squidex.Domain.Apps.Read.Rules;
using Squidex.Domain.Apps.Read.Schemas;
using Squidex.Infrastructure.CQRS.Events;
using Squidex.Infrastructure.Json.Orleans;
namespace Squidex.Domain.Apps.Read.State.Orleans.Grains
{
public interface IAppStateGrain : IGrainWithStringKey
{
Task<Immutable<(IAppEntity, ISchemaEntity)>> GetAppWithSchemaAsync(Guid id);
Task<J<(IAppEntity, ISchemaEntity)>> GetAppWithSchemaAsync(Guid id);
Task<Immutable<IAppEntity>> GetAppAsync();
Task<J<IAppEntity>> GetAppAsync();
Task<Immutable<ISchemaEntity>> GetSchemaAsync(Guid id, bool provideDeleted = false);
Task<J<ISchemaEntity>> GetSchemaAsync(Guid id, bool provideDeleted = false);
Task<Immutable<ISchemaEntity>> GetSchemaAsync(string name, bool provideDeleted = false);
Task<J<ISchemaEntity>> GetSchemaAsync(string name, bool provideDeleted = false);
Task<Immutable<List<ISchemaEntity>>> GetSchemasAsync();
Task<J<List<ISchemaEntity>>> GetSchemasAsync();
Task<Immutable<List<IRuleEntity>>> GetRulesAsync();
Task<J<List<IRuleEntity>>> GetRulesAsync();
Task HandleAsync(Immutable<Envelope<IEvent>> message);
Task HandleAsync(J<Envelope<IEvent>> message);
}
}

28
src/Squidex.Domain.Apps.Read/State/Orleans/Grains/Implementations/AppStateGrain.cs

@ -9,7 +9,6 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Orleans.Concurrency;
using Orleans.Runtime;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Events.Apps;
@ -18,6 +17,7 @@ using Squidex.Domain.Apps.Read.Rules;
using Squidex.Domain.Apps.Read.Schemas;
using Squidex.Infrastructure;
using Squidex.Infrastructure.CQRS.Events;
using Squidex.Infrastructure.Json.Orleans;
using Squidex.Infrastructure.Orleans;
namespace Squidex.Domain.Apps.Read.State.Orleans.Grains.Implementations
@ -57,49 +57,49 @@ namespace Squidex.Domain.Apps.Read.State.Orleans.Grains.Implementations
return base.OnActivateAsync();
}
public Task<Immutable<(IAppEntity, ISchemaEntity)>> GetAppWithSchemaAsync(Guid id)
public Task<J<(IAppEntity, ISchemaEntity)>> GetAppWithSchemaAsync(Guid id)
{
var schema = State.FindSchema(x => x.Id == id && !x.IsDeleted);
return Task.FromResult((State.GetApp(), schema).AsImmutable());
return Task.FromResult((State.GetApp(), schema).AsJ());
}
public Task<Immutable<IAppEntity>> GetAppAsync()
public Task<J<IAppEntity>> GetAppAsync()
{
var value = State.GetApp();
return Task.FromResult(value.AsImmutable());
return Task.FromResult(value.AsJ());
}
public Task<Immutable<List<IRuleEntity>>> GetRulesAsync()
public Task<J<List<IRuleEntity>>> GetRulesAsync()
{
var value = State.FindRules();
return Task.FromResult(value.AsImmutable());
return Task.FromResult(value.AsJ());
}
public Task<Immutable<List<ISchemaEntity>>> GetSchemasAsync()
public Task<J<List<ISchemaEntity>>> GetSchemasAsync()
{
var value = State.FindSchemas(x => !x.IsDeleted);
return Task.FromResult(value.AsImmutable());
return Task.FromResult(value.AsJ());
}
public Task<Immutable<ISchemaEntity>> GetSchemaAsync(Guid id, bool provideDeleted = false)
public Task<J<ISchemaEntity>> GetSchemaAsync(Guid id, bool provideDeleted = false)
{
var value = State.FindSchema(x => x.Id == id && (!x.IsDeleted || provideDeleted));
return Task.FromResult(value.AsImmutable());
return Task.FromResult(value.AsJ());
}
public Task<Immutable<ISchemaEntity>> GetSchemaAsync(string name, bool provideDeleted = false)
public Task<J<ISchemaEntity>> GetSchemaAsync(string name, bool provideDeleted = false)
{
var value = State.FindSchema(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase) && (!x.IsDeleted || provideDeleted));
return Task.FromResult(value.AsImmutable());
return Task.FromResult(value.AsJ());
}
public Task HandleAsync(Immutable<Envelope<IEvent>> message)
public Task HandleAsync(J<Envelope<IEvent>> message)
{
if (exception != null)
{

17
src/Squidex.Infrastructure/Json/Orleans/IJsonValue.cs

@ -0,0 +1,17 @@
// ==========================================================================
// IJsonValue.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
namespace Squidex.Infrastructure.Json.Orleans
{
public interface IJsonValue
{
object Value { get; }
bool IsImmutable { get; }
}
}

57
src/Squidex.Infrastructure/Json/Orleans/J.cs

@ -0,0 +1,57 @@
// ==========================================================================
// J.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace Squidex.Infrastructure.Json.Orleans
{
public struct J<T> : IJsonValue
{
private readonly T value;
private readonly bool isImmutable;
public T Value
{
get { return value; }
}
bool IJsonValue.IsImmutable
{
get { return isImmutable; }
}
object IJsonValue.Value
{
get { return Value; }
}
[JsonConstructor]
public J(T value, bool isImmutable = false)
{
this.value = value;
this.isImmutable = isImmutable;
}
public static implicit operator T(J<T> value)
{
return value.Value;
}
public static implicit operator J<T>(T d)
{
return new J<T>(d);
}
public static Task<J<T>> AsTask(T value)
{
return Task.FromResult<J<T>>(value);
}
}
}

18
src/Squidex.Infrastructure/Json/Orleans/JExtensions.cs

@ -0,0 +1,18 @@
// ==========================================================================
// JExtensions.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
namespace Squidex.Infrastructure.Json.Orleans
{
public static class JExtensions
{
public static J<T> AsJ<T>(this T value, bool immutable = true)
{
return new J<T>(value, immutable);
}
}
}

21
src/Squidex.Infrastructure/Json/Orleans/JsonExternalSerializer.cs

@ -7,8 +7,8 @@
// ==========================================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Orleans.Runtime;
@ -19,15 +19,12 @@ namespace Squidex.Infrastructure.Json.Orleans
public class JsonExternalSerializer : IExternalSerializer
{
private readonly JsonSerializer serializer;
private readonly HashSet<Type> types;
public JsonExternalSerializer(JsonSerializer serializer, params Type[] types)
public JsonExternalSerializer(JsonSerializer serializer)
{
Guard.NotNull(serializer, nameof(serializer));
this.serializer = serializer;
this.types = new HashSet<Type>(types);
}
public void Initialize(Logger logger)
@ -36,15 +33,25 @@ namespace Squidex.Infrastructure.Json.Orleans
public bool IsSupportedType(Type itemType)
{
return types.Contains(itemType);
return itemType.GetInterfaces().Contains(typeof(IJsonValue));
}
public object DeepCopy(object source, ICopyContext context)
{
if (source == null)
var jsonValue = source as IJsonValue;
if (jsonValue == null)
{
return null;
}
else if (jsonValue.IsImmutable)
{
return jsonValue;
}
else if (jsonValue.Value == null)
{
return jsonValue;
}
else
{
return JObject.FromObject(source, serializer).ToObject(source.GetType(), serializer);

4
src/Squidex/Config/Orleans/CustomJsonSerializer.cs

@ -8,7 +8,6 @@
using Newtonsoft.Json;
using Squidex.Config.Domain;
using Squidex.Infrastructure.CQRS.Events;
using Squidex.Infrastructure.Json.Orleans;
namespace Squidex.Config.Orleans
@ -16,8 +15,7 @@ namespace Squidex.Config.Orleans
public class CustomJsonSerializer : JsonExternalSerializer
{
public CustomJsonSerializer()
: base(JsonSerializer.Create(SerializationServices.DefaultJsonSettings),
typeof(Envelope<IEvent>))
: base(JsonSerializer.Create(SerializationServices.DefaultJsonSettings))
{
}
}

55
tests/Squidex.Infrastructure.Tests/Json/Orleans/JsonExternalSerializerTests.cs

@ -22,38 +22,54 @@ namespace Squidex.Infrastructure.Json.Orleans
[Fact]
public void Should_serialize_js_only()
{
var serializer = new JsonExternalSerializer(JsonSerializer.CreateDefault(), typeof(int), typeof(bool));
Assert.True(sut.IsSupportedType(typeof(J<int>)));
Assert.True(sut.IsSupportedType(typeof(J<List<int>>)));
Assert.True(sut.IsSupportedType(typeof(int)));
Assert.True(sut.IsSupportedType(typeof(bool)));
Assert.False(sut.IsSupportedType(typeof(float)));
Assert.False(sut.IsSupportedType(typeof(double)));
Assert.False(sut.IsSupportedType(typeof(int)));
Assert.False(sut.IsSupportedType(typeof(List<int>)));
}
[Fact]
public void Should_copy_null()
{
var value = (string)null;
var copy = sut.DeepCopy(value, null);
var v = (string)null;
var c = DeepCopy(v);
Assert.Null(c);
}
[Fact]
public void Should_copy_null_json()
{
var v = new J<List<int>>(null);
var c = DeepCopy(v);
Assert.Null(c.Value);
}
[Fact]
public void Should_not_copy_immutable_values()
{
var v = new List<int> { 1, 2, 3 }.AsJ(true);
var c = DeepCopy(v);
Assert.Null(copy);
Assert.Same(v.Value, c.Value);
}
[Fact]
public void Should_copy_non_immutable_values()
{
var value = new List<int> { 1, 2, 3 };
var copy = (List<int>)sut.DeepCopy(value, null);
var value = new J<List<int>>(new List<int> { 1, 2, 3 });
var copy = (J<List<int>>)sut.DeepCopy(value, null);
Assert.Equal(value, copy);
Assert.NotSame(value, copy);
Assert.Equal(value.Value, copy.Value);
Assert.NotSame(value.Value, copy.Value);
}
[Fact]
public void Should_serialize_and_deserialize_value()
{
var value = new List<int>(new List<int> { 1, 2, 3 });
var value = new J<List<int>>(new List<int> { 1, 2, 3 });
var writtenLength = 0;
var writtenBuffer = (byte[])null;
@ -78,10 +94,15 @@ namespace Squidex.Infrastructure.Json.Orleans
A.CallTo(() => reader.ReadBytes(writtenLength))
.Returns(writtenBuffer);
var copy = (List<int>)sut.Deserialize(value.GetType(), readerContext);
var copy = (J<List<int>>)sut.Deserialize(value.GetType(), readerContext);
Assert.Equal(value, copy);
Assert.NotSame(value, copy);
Assert.Equal(value.Value, copy.Value);
Assert.NotSame(value.Value, copy.Value);
}
private T DeepCopy<T>(T value)
{
return (T)sut.DeepCopy(value, null);
}
}
}

Loading…
Cancel
Save