//******************************************************************************************************
// Serialization.cs - Gbtc
//
// Copyright © 2012, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may
// not use this file except in compliance with the License. You may obtain a copy of the License at:
//
// http://www.opensource.org/licenses/MIT
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 06/08/2006 - Pinal C. Patel
// Original version of source code generated.
// 09/09/2008 - J. Ritchie Carroll
// Converted to C#.
// 09/09/2008 - J. Ritchie Carroll
// Added TryGetObject overloads.
// 02/16/2009 - Josh L. Patterson
// Edited Code Comments.
// 08/4/2009 - Josh L. Patterson
// Edited Code Comments.
// 09/14/2009 - Stephen C. Wills
// Added new header and license agreement.
// 04/06/2011 - Pinal C. Patel
// Modified GetString() method to not check for the presence of Serializable attribute on the
// object being serialized since this is not required by the XmlSerializer.
// 04/08/2011 - Pinal C. Patel
// Moved Serialize() and Deserialize() methods from GSF.Services.ServiceModel.Serialization class
// in GSF.Services.dll to consolidate serialization methods.
// 12/14/2012 - Starlynn Danyelle Gilliam
// Modified Header.
//
//******************************************************************************************************
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Json;
using System.ServiceModel;
using System.Xml.Serialization;
using GSF.IO;
using GSF.Reflection;
namespace GSF
{
#region [ Enumerations ]
///
/// Indicates the format of serialization or deserialization.
///
public enum SerializationFormat
{
///
/// is serialized or deserialized using to XML (eXtensible Markup Language) format.
///
///
/// can be serialized or deserialized using by adding the to the .
///
Xml,
///
/// is serialized or deserialized using to JSON (JavaScript Object Notation) format.
///
Json,
///
/// is serialized or deserialized using to binary format.
///
Binary
}
#endregion
///
/// Common serialization related functions.
///
public static class Serialization
{
#region [ Obsolete ]
///
/// Creates a clone of a serializable object.
///
/// The type of the cloned object.
/// The type source to be cloned.
/// A clone of .
[Obsolete("This method will be removed in future builds.")]
public static T CloneObject(T sourceObject)
{
return Deserialize(Serialize(sourceObject, SerializationFormat.Binary), SerializationFormat.Binary);
}
///
/// Performs XML deserialization on the XML string and returns the typed object for it.
///
///
/// This function will throw an error during deserialization if the input data is invalid,
/// consider using TryGetObject to prevent needing to implement exception handling.
///
///
/// An error occurred during deserialization. The original exception is available using
/// the InnerException property.
///
/// The type of the object to create from the serialized string .
/// A representing the object () to deserialize.
/// A type T based on .
[Obsolete("This method will be removed in future builds, use the Deserialize() method instead.")]
public static T GetObject(string serializedObject)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(new StringReader(serializedObject));
}
///
/// Attempts XML deserialization on the XML string and returns the typed object for it.
///
/// The generic type T that is to be deserialized.
/// that contains the serialized representation of the object.
/// An object of type T that is passed in as the container to hold the deserialized object from the string .
/// value indicating if the deserialization was successful.
[Obsolete("This method will be removed in future builds, use the Deserialize() method instead.")]
public static bool TryGetObject(string serializedObject, out T deserializedObject)
{
try
{
deserializedObject = GetObject(serializedObject);
return true;
}
catch
{
deserializedObject = default(T);
return false;
}
}
///
/// Performs binary deserialization on the byte array and returns the typed object for it.
///
///
/// This function will throw an error during deserialization if the input data is invalid,
/// consider using TryGetObject to prevent needing to implement exception handling.
///
/// Serialized object data is invalid or length is 0.
/// The caller does not have the required permission.
/// The type of the object to create from the serialized byte array .
/// A array representing the object () to deserialize.
/// A type T based on .
[Obsolete("This method will be removed in future builds, use the Deserialize() method instead.")]
public static T GetObject(byte[] serializedObject)
{
BinaryFormatter serializer = new BinaryFormatter();
return (T)serializer.Deserialize(new MemoryStream(serializedObject));
}
///
/// Attempts binary deserialization on the byte array and returns the typed object for it.
///
/// A array representing the object () to deserialize.
/// A type T object, passed by reference, that is used to be hold the deserialized object.
/// The generic type T that is to be deserialized.
/// A which indicates whether the deserialization process was successful.
[Obsolete("This method will be removed in future builds, use the Deserialize() method instead.")]
public static bool TryGetObject(byte[] serializedObject, out T deserializedObject)
{
try
{
deserializedObject = GetObject(serializedObject);
return true;
}
catch
{
deserializedObject = default(T);
return false;
}
}
///
/// Performs binary deserialization on the byte array and returns the object for it.
///
///
/// This function will throw an error during deserialization if the input data is invalid,
/// consider using TryGetObject to prevent needing to implement exception handling.
///
/// Serialized object data is invalid or length is 0.
/// The caller does not have the required permission.
/// A array representing the object () to deserialize.
/// An based on .
[Obsolete("This method will be removed in future builds, use the Deserialize() method instead.")]
public static object GetObject(byte[] serializedObject)
{
BinaryFormatter serializer = new BinaryFormatter();
return serializer.Deserialize(new MemoryStream(serializedObject));
}
///
/// Attempts binary deserialization on the byte array and returns the typed object for it.
///
/// A array representing the object () to deserialize.
/// An , passed by reference, that is used to be hold the deserialized object.
/// A which indicates whether the deserialization process was successful.
[Obsolete("This method will be removed in future builds, use the Deserialize() method instead.")]
public static bool TryGetObject(byte[] serializedObject, out object deserializedObject)
{
try
{
deserializedObject = GetObject(serializedObject);
return true;
}
catch
{
deserializedObject = null;
return false;
}
}
///
/// Performs XML serialization on the serializable object and returns the output as string.
///
/// The serializable object.
/// An XML representation of the object if the specified object can be serialized; otherwise an empty string.
[Obsolete("This method will be removed in future builds, use the Serialize() method instead.")]
public static string GetString(object serializableObject)
{
StringWriter serializedObject = new StringWriter();
XmlSerializer serializer = new XmlSerializer(serializableObject.GetType());
serializer.Serialize(serializedObject, serializableObject);
return serializedObject.ToString();
}
///
/// Performs binary serialization on the serializable object and returns the output as byte array.
///
/// The serializable object.
/// A byte array representation of the object if the specified object can be serialized; otherwise an empty array.
[Obsolete("This method will be removed in future builds, use the Serialize() method instead.")]
public static byte[] GetBytes(object serializableObject)
{
return GetStream(serializableObject).ToArray();
}
///
/// Performs binary serialization on the serializable object and returns the serialized object as a stream.
///
/// The serializable object.
/// A memory stream representation of the object if the specified object can be serialized; otherwise an empty stream.
[Obsolete("This method will be removed in future builds, use the Serialize() method instead.")]
public static MemoryStream GetStream(object serializableObject)
{
MemoryStream dataStream = new MemoryStream();
if (serializableObject.GetType().IsSerializable)
{
BinaryFormatter serializer = new BinaryFormatter();
serializer.Serialize(dataStream, serializableObject);
}
return dataStream;
}
#endregion
#region [ Legacy ]
///
/// Serialization binder used to deserialize files that were serialized using the old library frameworks
/// (TVA Code Library, Time Series Framework, TVA.PhasorProtocols, and PMU Connection Tester) into classes
/// in the Grid Solutions Framework.
///
[SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
public static readonly SerializationBinder LegacyBinder = new LegacySerializationBinder();
// Serialization binder used to deserialize files that were serialized using the old library frameworks.
private class LegacySerializationBinder : SerializationBinder
{
///
/// Controls the binding of a serialized object to a type.
///
/// Specifies the name of the serialized object.
/// Specifies the name of the serialized object.
/// The type of the object the formatter creates a new instance of.
public override Type BindToType(string assemblyName, string typeName)
{
// Perform namespace transformations that occurred when migrating to the Grid Solutions Framework
// from various older versions of code with different namespaces
string newTypeName = typeName
.Replace("TVA.", "GSF.")
.Replace("TimeSeriesFramework.", "GSF.TimeSeries.")
.Replace("ConnectionTester.", "GSF.PhasorProtocols.") // PMU Connection Tester namespace
.Replace("TVA.Phasors.", "GSF.PhasorProtocols.") // 2007 TVA Code Library namespace
.Replace("Tva.Phasors.", "GSF.PhasorProtocols.") // 2008 TVA Code Library namespace
.Replace("BpaPdcStream", "BPAPDCstream") // 2013 GSF uppercase phasor protocol namespace
.Replace("FNet", "FNET") // 2013 GSF uppercase phasor protocol namespace
.Replace("Iec61850_90_5", "IEC61850_90_5") // 2013 GSF uppercase phasor protocol namespace
.Replace("Ieee1344", "IEEE1344") // 2013 GSF uppercase phasor protocol namespace
.Replace("IeeeC37_118", "IEEEC37_118"); // 2013 GSF uppercase phasor protocol namespace
// Check for 2009 TVA Code Library namespace
if (newTypeName.StartsWith("PhasorProtocols", StringComparison.Ordinal))
newTypeName = "GSF." + newTypeName;
// Check for 2014 LineFrequency type in the GSF phasor protocol namespace
if (newTypeName.Equals("GSF.PhasorProtocols.LineFrequency", StringComparison.Ordinal))
newTypeName = "GSF.Units.EE.LineFrequency";
try
{
// Search each assembly in the current application domain for the type with the transformed name
return AssemblyInfo.FindType(newTypeName);
}
catch
{
// Fall back on more brute force search when simple search fails
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
Type newType = assembly.GetType(newTypeName);
if ((object)newType != null)
return newType;
}
catch
{
// Ignore errors that occur when attempting to load
// types from assemblies as we may still be able to
// load the type from a different assembly
}
}
}
// No type found; return null
return null;
}
}
#endregion
///
/// Serializes an .
///
/// of the .
/// to be serialized.
/// in which the is to be serialized.
/// An of of the serialized .
/// is null.
/// Specified is not supported.
public static byte[] Serialize(T serializableObject, SerializationFormat serializationFormat)
{
// FYI, using statement will not work here as this creates a read-only variable that cannot be passed by reference
Stream stream = null;
try
{
stream = new BlockAllocatedMemoryStream();
Serialize(serializableObject, serializationFormat, stream);
return ((BlockAllocatedMemoryStream)stream).ToArray();
}
finally
{
stream?.Dispose();
}
}
///
/// Serializes an .
///
/// of the .
/// to be serialized.
/// in which the is to be serialized.
/// where the is to be serialized.
/// or is null.
/// Specified is not supported.
public static void Serialize(T serializableObject, SerializationFormat serializationFormat, Stream serializedOutput)
{
if (serializedOutput == null)
throw new ArgumentNullException(nameof(serializedOutput));
if (serializableObject == null)
throw new ArgumentNullException(nameof(serializableObject));
switch (serializationFormat)
{
// Serialize object to the provided stream.
case SerializationFormat.Xml when typeof(T).GetCustomAttributes(typeof(XmlSerializerFormatAttribute), false).Length > 0:
{
// Serialize to XML format using XmlSerializer.
XmlSerializer serializer = new XmlSerializer(typeof(T));
serializer.Serialize(serializedOutput, serializableObject);
break;
}
case SerializationFormat.Xml:
{
// Serialize to XML format using DataContractSerializer.
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
serializer.WriteObject(serializedOutput, serializableObject);
break;
}
case SerializationFormat.Json:
{
// Serialize to JSON format.
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
serializer.WriteObject(serializedOutput, serializableObject);
break;
}
case SerializationFormat.Binary:
{
// Serialize to binary format.
BinaryFormatter serializer = new BinaryFormatter();
serializer.Serialize(serializedOutput, serializableObject);
break;
}
default:
// Serialization format is not supported.
throw new NotSupportedException($"{serializationFormat} serialization is not supported");
}
// Seek to the beginning of the serialized output stream.
serializedOutput.Position = 0;
}
///
/// Deserializes a serialized .
///
/// of the deserialized to be returned.
/// of s containing the serialized that is to be deserialized.
/// in which the was serialized.
/// The deserialized .
/// is null.
/// Specified is not supported.
public static T Deserialize(byte[] serializedObject, SerializationFormat serializationFormat)
{
if (serializedObject == null)
throw new ArgumentNullException(nameof(serializedObject));
using MemoryStream stream = new MemoryStream(serializedObject);
return Deserialize(stream, serializationFormat);
}
///
/// Deserializes a serialized .
///
/// of the deserialized to be returned.
/// containing the serialized that is to be deserialized.
/// in which the was serialized.
/// The deserialized .
/// is null.
/// Specified is not supported.
public static T Deserialize(Stream serializedObject, SerializationFormat serializationFormat)
{
if (serializedObject == null)
throw new ArgumentNullException(nameof(serializedObject));
// Deserialize the serialized object.
T deserializedObject;
switch (serializationFormat)
{
case SerializationFormat.Xml when typeof(T).GetCustomAttributes(typeof(XmlSerializerFormatAttribute), false).Length > 0:
{
// Deserialize from XML format using XmlSerializer.
XmlSerializer serializer = new XmlSerializer(typeof(T));
deserializedObject = (T)serializer.Deserialize(serializedObject);
break;
}
case SerializationFormat.Xml:
{
// Deserialize from XML format using DataContractSerializer.
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
deserializedObject = (T)serializer.ReadObject(serializedObject);
break;
}
case SerializationFormat.Json:
{
// Deserialize from JSON format.
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
deserializedObject = (T)serializer.ReadObject(serializedObject);
break;
}
case SerializationFormat.Binary:
{
// Deserialize from binary format.
BinaryFormatter serializer = new BinaryFormatter();
serializer.Binder = LegacyBinder;
deserializedObject = (T)serializer.Deserialize(serializedObject);
break;
}
default:
// Serialization format is not supported.
throw new NotSupportedException($"{serializationFormat} serialization is not supported");
}
return deserializedObject;
}
///
/// Attempts to deserialize a serialized .
///
/// of the deserialized to be returned.
/// of s containing the serialized that is to be deserialized.
/// in which the was serialized.
/// Deserialized .
/// trueif deserialization succeeded; otherwise false.
public static bool TryDeserialize(byte[] serializedObject, SerializationFormat serializationFormat, out T deserializedObject)
{
deserializedObject = default(T);
try
{
deserializedObject = Deserialize(serializedObject, serializationFormat);
return true;
}
catch
{
return false;
}
}
///
/// Attempts to deserialize a serialized .
///
/// of the deserialized to be returned.
/// containing the serialized that is to be deserialized.
/// in which the was serialized.
/// Deserialized .
/// trueif deserialization succeeded; otherwise false.
public static bool TryDeserialize(Stream serializedObject, SerializationFormat serializationFormat, out T deserializedObject)
{
deserializedObject = default(T);
try
{
deserializedObject = Deserialize(serializedObject, serializationFormat);
return true;
}
catch
{
return false;
}
}
///
/// Gets value for specified ; otherwise .
///
/// Type of parameter to get from .
/// object that contains deserialized values.
/// Name of deserialized parameter to retrieve.
/// Default value to return if does not exist or cannot be deserialized.
/// Value for specified ; otherwise
///
/// do not have a direct way of determining if an item with a specified name exists, so when calling
/// one of the Get(n) functions you will simply get a if the parameter does not exist; similarly
/// you will receive this exception if the parameter fails to properly deserialize. This extension method protects against both of
/// these failures and returns a default value if the named parameter does not exist or cannot be deserialized.
///
public static T GetOrDefault(this SerializationInfo info, string name, T defaultValue)
{
try
{
return (T)info.GetValue(name, typeof(T));
}
catch (SerializationException)
{
return defaultValue;
}
}
///
/// Gets values of a instance compatible with Linq operations.
///
/// Target instance.
/// Enumeration of objects from instance.
public static IEnumerable GetValues(this SerializationInfo info)
{
SerializationInfoEnumerator enumerator = info.GetEnumerator();
{
while (enumerator.MoveNext())
yield return enumerator.Current;
}
}
}
}