Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Coreclr compatibility: Implemented Json.Net fallback serializer #1047

Merged
merged 1 commit into from
Nov 26, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/Orleans/Configuration/MessagingConfiguration.cs
Expand Up @@ -132,6 +132,7 @@ public class MessagingConfiguration : IMessagingConfiguration
public int GatewaySenderQueues { get; set; }
public int ClientSenderBuckets { get; set; }
public bool UseStandardSerializer { get; set; }
public bool UseJsonFallbackSerializer { get; set; }

public int BufferPoolBufferSize { get; set; }
public int BufferPoolMaxSize { get; set; }
Expand Down Expand Up @@ -226,6 +227,8 @@ public override string ToString()
}
sb.AppendFormat(" Use standard (.NET) serializer: {0}", UseStandardSerializer)
.AppendLine(isSiloConfig ? "" : " [NOTE: This *MUST* match the setting on the server or nothing will work!]");
sb.AppendFormat(" Use fallback json serializer: {0}", UseJsonFallbackSerializer)
.AppendLine(isSiloConfig ? "" : " [NOTE: This *MUST* match the setting on the server or nothing will work!]");
sb.AppendFormat(" Buffer Pool Buffer Size: {0}", BufferPoolBufferSize).AppendLine();
sb.AppendFormat(" Buffer Pool Max Size: {0}", BufferPoolMaxSize).AppendLine();
sb.AppendFormat(" Buffer Pool Preallocation Size: {0}", BufferPoolPreallocationSize).AppendLine();
Expand Down Expand Up @@ -298,6 +301,13 @@ internal virtual void Load(XmlElement child)
"invalid boolean value for the UseStandardSerializer attribute on the Messaging element");
}

if (child.HasAttribute("UseJsonFallbackSerializer"))
{
UseJsonFallbackSerializer =
ConfigUtilities.ParseBool(child.GetAttribute("UseJsonFallbackSerializer"),
"invalid boolean value for the UseJsonFallbackSerializer attribute on the Messaging element");
}

//--
if (child.HasAttribute("BufferPoolBufferSize"))
{
Expand Down
2 changes: 2 additions & 0 deletions src/Orleans/IDs/ActivationAddress.cs
Expand Up @@ -22,6 +22,7 @@ MIT License
*/

using System;
using Newtonsoft.Json;

namespace Orleans.Runtime
{
Expand All @@ -37,6 +38,7 @@ public bool IsComplete
get { return Grain != null && Activation != null && Silo != null; }
}

[JsonConstructor]
private ActivationAddress(SiloAddress silo, GrainId grain, ActivationId activation)
{
Silo = silo;
Expand Down
2 changes: 2 additions & 0 deletions src/Orleans/IDs/UniqueIdentifier.cs
Expand Up @@ -22,13 +22,15 @@ MIT License
*/

using System;
using Newtonsoft.Json;

namespace Orleans.Runtime
{
[Serializable]
internal abstract class UniqueIdentifier : IEquatable<UniqueIdentifier>, IComparable<UniqueIdentifier>
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
[JsonProperty]
protected readonly internal UniqueKey Key;

protected UniqueIdentifier()
Expand Down
1 change: 1 addition & 0 deletions src/Orleans/Logging/ErrorCodes.cs
Expand Up @@ -903,6 +903,7 @@ internal enum ErrorCode
SerMgr_IgnoreAssembly = SerializationManagerBase + 8,
SerMgr_TypeRegistrationFailureIgnore = SerializationManagerBase + 9,
SerMgr_ArtifactReport = SerializationManagerBase + 10,
SerMgr_UnavailableSerializer = SerializationManagerBase + 11,

WatchdogBase = Runtime + 2600,
Watchdog_ParticipantThrownException = WatchdogBase + 1,
Expand Down
7 changes: 6 additions & 1 deletion src/Orleans/Orleans.csproj
Expand Up @@ -74,6 +74,9 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Newtonsoft.Json">
<HintPath>$(SolutionDir)packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Management" />
<Reference Include="System.Xml" />
Expand Down Expand Up @@ -124,6 +127,8 @@
<Compile Include="IDs\UniqueKey.cs" />
<Compile Include="Core\IGrainFactory.cs" />
<Compile Include="Runtime\IGrainRuntime.cs" />
<Compile Include="Serialization\OrleansJsonSerializer.cs" />
<Compile Include="Serialization\BinaryFormatterSerializer.cs" />
<Compile Include="Streams\Internal\StreamHandshakeToken.cs" />
<Compile Include="Serialization\NonSerializableAttribute.cs" />
<Compile Include="Streams\PersistentStreams\IDeploymentConfiguration.cs" />
Expand Down Expand Up @@ -429,4 +434,4 @@
<Message Text="[OrleansDllBootstrapUsingCodeGen] - Invoking Code Generator" />
<Exec Command="&quot;$(BootstrapOutputPath)ClientGenerator.exe&quot; &quot;@$(ArgsFile)&quot;" />
</Target>
</Project>
</Project>
2 changes: 1 addition & 1 deletion src/Orleans/Runtime/OutsideRuntimeClient.cs
Expand Up @@ -154,7 +154,7 @@ public OutsideRuntimeClient(ClientConfiguration cfg, GrainFactory grainFactory,

if (!TraceLogger.IsInitialized) TraceLogger.Initialize(config);
StatisticsCollector.Initialize(config);
SerializationManager.Initialize(config.UseStandardSerializer, cfg.SerializationProviders);
SerializationManager.Initialize(config.UseStandardSerializer, cfg.SerializationProviders, config.UseJsonFallbackSerializer);
logger = TraceLogger.GetLogger("OutsideRuntimeClient", TraceLogger.LoggerType.Runtime);
appLogger = TraceLogger.GetLogger("Application", TraceLogger.LoggerType.Application);

Expand Down
130 changes: 130 additions & 0 deletions src/Orleans/Serialization/BinaryFormatterSerializer.cs
@@ -0,0 +1,130 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
using Orleans.Runtime;

#if !DNXCORE50
namespace Orleans.Serialization
{
public class BinaryFormatterSerializer : IExternalSerializer
{
private TraceLogger logger;
public void Initialize(TraceLogger logger)
{
this.logger = logger;
}

public bool IsSupportedType(Type itemType)
{
return itemType.GetTypeInfo().IsSerializable;
}

public object DeepCopy(object source)
{
if (source == null)
{
return null;
}

var formatter = new BinaryFormatter();
object ret = null;
using (var memoryStream = new MemoryStream())
{
formatter.Serialize(memoryStream, source);
memoryStream.Flush();
memoryStream.Seek(0, SeekOrigin.Begin);
formatter.Binder = DynamicBinder.Instance;
ret = formatter.Deserialize(memoryStream);
}

return ret;
}

public void Serialize(object item, BinaryTokenStreamWriter writer, Type expectedType)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}

if (item == null)
{
writer.WriteNull();
return;
}

var formatter = new BinaryFormatter();
byte[] bytes;
using (var memoryStream = new MemoryStream())
{
formatter.Serialize(memoryStream, item);
memoryStream.Flush();
bytes = memoryStream.ToArray();
}

writer.Write(bytes.Length);
writer.Write(bytes);
}

public object Deserialize(Type expectedType, BinaryTokenStreamReader reader)
{
if (reader == null)
{
throw new ArgumentNullException("reader");
}

var n = reader.ReadInt();
var bytes = reader.ReadBytes(n);
var formatter = new BinaryFormatter();
object retVal = null;
using (var memoryStream = new MemoryStream(bytes))
{
retVal = formatter.Deserialize(memoryStream);
}

return retVal;
}


/// <summary>
/// This appears necessary because the BinaryFormatter by default will not see types
/// that are defined by the InvokerGenerator.
/// Needs to be public since it used by generated client code.
/// </summary>
class DynamicBinder : SerializationBinder
{
public static readonly SerializationBinder Instance = new DynamicBinder();

private readonly Dictionary<string, Assembly> assemblies = new Dictionary<string, Assembly>();

public override Type BindToType(string assemblyName, string typeName)
{
lock (this.assemblies)
{
Assembly result;
if (!this.assemblies.TryGetValue(assemblyName, out result))
{
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
this.assemblies[assembly.GetName().FullName] = assembly;

// in some cases we have to explicitly load the assembly even though it seems to be already loaded but for some reason it's not listed in AppDomain.CurrentDomain.GetAssemblies()
if (!this.assemblies.TryGetValue(assemblyName, out result))
this.assemblies[assemblyName] = Assembly.Load(new AssemblyName(assemblyName));

result = this.assemblies[assemblyName];
}

return result.GetType(typeName);
}
}
}
}
}
#endif