//****************************************************************************************************** // 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.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) { Type newType; string newTypeName; // Perform namespace transformations that occurred when migrating to the Grid Solutions Framework // from various older versions of code with different namespaces 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 { 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 { if ((object)stream != null) 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 ((object)serializedOutput == null) throw new ArgumentNullException(nameof(serializedOutput)); if ((object)serializableObject == null) throw new ArgumentNullException(nameof(serializableObject)); // Serialize object to the provided stream. if (serializationFormat == SerializationFormat.Xml) { if (typeof(T).GetCustomAttributes(typeof(XmlSerializerFormatAttribute), false).Length > 0) { // Serialize to XML format using XmlSerializer. XmlSerializer serializer = new XmlSerializer(typeof(T)); serializer.Serialize(serializedOutput, serializableObject); } else { // Serialize to XML format using DataContractSerializer. DataContractSerializer serializer = new DataContractSerializer(typeof(T)); serializer.WriteObject(serializedOutput, serializableObject); } } else if (serializationFormat == SerializationFormat.Json) { // Serialize to JSON format. DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T)); serializer.WriteObject(serializedOutput, serializableObject); } else if (serializationFormat == SerializationFormat.Binary) { // Serialize to binary format. BinaryFormatter serializer = new BinaryFormatter(); serializer.Serialize(serializedOutput, serializableObject); } else { // Serialization format is not supported. throw new NotSupportedException(string.Format("{0} serialization is not supported", serializationFormat)); } // 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 ((object)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 ((object)serializedObject == null) throw new ArgumentNullException(nameof(serializedObject)); // Deserialize the serialized object. T deserializedObject; if (serializationFormat == SerializationFormat.Xml) { if (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); } else { // Deserialize from XML format using DataContractSerializer. DataContractSerializer serializer = new DataContractSerializer(typeof(T)); deserializedObject = (T)serializer.ReadObject(serializedObject); } } else if (serializationFormat == SerializationFormat.Json) { // Deserialize from JSON format. DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T)); deserializedObject = (T)serializer.ReadObject(serializedObject); } else if (serializationFormat == SerializationFormat.Binary) { // Deserialize from binary format. BinaryFormatter serializer = new BinaryFormatter(); serializer.Binder = LegacyBinder; deserializedObject = (T)serializer.Deserialize(serializedObject); } else { // Serialization format is not supported. throw new NotSupportedException(string.Format("{0} serialization is not supported", serializationFormat)); } 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; } } } }