DataContractSerializer

namespace Core.Utility
{
   using System;
   using System.IO;
   using System.Linq;
   using System.Runtime.Serialization;
   using System.Text;
   using System.Xml;
   using System.Xml.Linq;
   using System.Collections.Generic;

   /// <summary>
   /// Class DataContractSerialization
   /// </summary>
   /// <remarks>
   /// Implemented for WCF DataContract Serialization
   /// </remarks>
   public class DataContractSerialization
   {
      /// <summary>
      /// Tries the serialize.
      /// </summary>
      /// <typeparam name="TValue">Type to convert</typeparam>
      /// <param name="objectToSerialize">The object to serialize.</param>
      /// <param name="outputValue">The output value.</param>
      /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
      public bool TrySerialize<TValue>(TValue objectToSerialize, out string outputValue)
         where TValue: class, new()
      {
         outputValue = string.Empty;

         try
         {
            outputValue = Serialize(objectToSerialize);
         }
         catch
         {
            return false;
         }

         return true;
      }

      /// <summary>
      /// Tries to deserialize the input xml as the specified TValue object
      /// </summary>
      /// <typeparam name="TValue">Object to cast the input Xml to</typeparam>
      /// <param name="inputXml">The input XML to bind</param>
      /// <param name="value">The output value if successful</param>
      /// <returns><c>true</c> if the deserialization was successful, <c>false</c> otherwise.</returns>
      public bool TryDeserialize<TValue>(string inputXml, out TValue value)
         where TValue: class, new()
      {
         value = default(TValue);

         try
         {
            value = Deserialize<TValue>(inputXml);
         }
         catch
         {
            return false;
         }

         return true;
      }

      /// <summary>
      /// Serializes the specified object to serialize.
      /// </summary>
      /// <typeparam name="TValue">Type to convert</typeparam>
      /// <param name="objectToSerialize">The object to serialize.</param>
      /// <returns>type converted to Xml</returns>
      /// <exception cref="InvalidDataContractException">Serialize</exception>
      public string Serialize<TValue>(TValue objectToSerialize)
        where TValue: class, new()
      {
         using (var memoryStream = new MemoryStream())
         {
            try
            {
               XmlObjectSerializer contractSerializer = new DataContractSerializer(
                  typeof(TValue),
                  null,
                  int.MaxValue,
                  false,
                  false,
                  null,
                  new ContractResourceResolver());

               contractSerializer.WriteObject(memoryStream, objectToSerialize);
               memoryStream.Position = 0;

               memoryStream.Seek(0, SeekOrigin.Begin);
            }
            catch (InvalidDataContractException exception)
            {
               throw new InvalidDataContractException(nameof(Serialize), exception);
            }

            using (var writer = new CustomXmlTextWriter(memoryStream) { Formatting = Formatting.Indented })
            {
               string xmlOutput = Encoding.UTF8.GetString(memoryStream.ToArray());

               return xmlOutput;
            }
         }
      }

      /// <summary>
      /// Deserialize the input xml as the specified TValue object
      /// </summary>
      /// <typeparam name="TValue">Object to cast the input Xml to</typeparam>
      /// <param name="value">The input XML to bind</param>
      /// <returns>Xml converted to type T</returns>
      /// <exception cref="InvalidDataContractException">Thrown if data contract is invalid</exception>
      /// <exception cref="Exception">Thrown if a generic error occurs</exception>
      public TValue Deserialize<TValue>(string value)
        where TValue: class, new()
      {
         if (string.IsNullOrEmpty(value))
         {
            throw new ArgumentNullException(nameof(value));
         }

         TValue deserializedPerson;
         XmlDictionaryReader textReader = null;

         byte[] xmlData = Encoding.UTF8.GetBytes(value);

         try
         {
            textReader = XmlDictionaryReader.CreateTextReader(xmlData, new XmlDictionaryReaderQuotas());

            XmlObjectSerializer contractSerializer = new DataContractSerializer(
               typeof(TValue),
               null,
               int.MaxValue,
               false,
               false,
               null,
               new ContractResourceResolver());

            deserializedPerson = (TValue)contractSerializer.ReadObject(textReader, true);
         }
         catch (InvalidDataContractException exception)
         {
            throw new InvalidDataContractException(nameof(Deserialize), exception);
         }
         catch (Exception exception)
         {
            throw new Exception(nameof(Deserialize), exception);
         }
         finally
         {
            if (textReader != null)
            {
               textReader.Close();
            }
         }

         return deserializedPerson;
      }

      /// <summary>
      /// Removes the XMLNS.
      /// </summary>
      /// <param name="xml">The XML.</param>
      /// <returns>Xml string without namespaces</returns>
      private string RemoveXmlns(string xml)
      {
         XDocument document = XDocument.Parse(xml);
         document.Root.Descendants().Attributes().Where(x => x.IsNamespaceDeclaration).Remove();

         foreach (var elem in document.Descendants())
         {
            elem.Name = elem.Name.LocalName;
         }

         var xmlDocument = new XmlDocument();
         xmlDocument.Load(document.CreateReader());

         return xmlDocument.OuterXml;
      }
   }


   /// <summary>
   /// Class ContractResourceResolver.
   /// </summary>
   /// <remarks>Object data</remarks>
   public class ContractResourceResolver : DataContractResolver
   {
      private static readonly Dictionary<string, Type> TypeDictionary = new Dictionary<string, Type>();

      /// <summary>
      /// Tries the type of the resolve.
      /// </summary>
      /// <param name="dataContractType">Type of the data contract.</param>
      /// <param name="declaredType">Type of the declared.</param>
      /// <param name="knownTypeResolver">The known type resolver.</param>
      /// <param name="typeName">Name of the type.</param>
      /// <param name="typeNamespace">The type namespace.</param>
      /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
      /// <remarks>Object data</remarks>
      public override bool TryResolveType(Type dataContractType,
                                          Type declaredType,
                                          DataContractResolver knownTypeResolver,
                                          out XmlDictionaryString typeName,
                                          out XmlDictionaryString typeNamespace)
      {
         if (!knownTypeResolver.TryResolveType(dataContractType, declaredType, null, out typeName, out typeNamespace))
         {
            var dictionary = new XmlDictionary();
            typeName = dictionary.Add(dataContractType.FullName);
            typeNamespace = dictionary.Add(dataContractType.Assembly.FullName);
         }

         return true;
      }

      /// <summary>
      /// Override this method to map the specified type name and namespace to a data contract type during deserialization.
      /// </summary>
      /// <param name="typeName">The type name to map.</param>
      /// <param name="typeNamespace">The type namespace to map.</param>
      /// <param name="declaredType">The type declared in the data contract.</param>
      /// <param name="knownTypeResolver">The known type resolver.</param>
      /// <returns>The type the type name and namespace is mapped to.</returns>
      /// <remarks>Object data</remarks>
      public override Type ResolveName(string typeName,
                                       string typeNamespace,
                                       Type declaredType,
                                       DataContractResolver knownTypeResolver)
      {
         Type type;
         if (TypeDictionary.ContainsKey(typeName))
         {
            if (TypeDictionary.TryGetValue(typeName, out type))
            {
               return type;
            }
         }

         IEnumerable<Type> types = from a in AppDomain.CurrentDomain.GetAssemblies()
                                   from t in a.GetTypes()
                                   where
                                      (!t.FullName.Contains("System.") && !t.FullName.Contains("Microsoft.")) &&
                                      t.Name.Equals(typeName)
                                   select t;

         IEnumerable<Type> enumerable = types as IList<Type> ?? types.ToList();
         if (enumerable.ToList()
                  .Count == 0)
         {
            return knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, knownTypeResolver);
         }

         type = enumerable.First();
         if (!TypeDictionary.ContainsKey(typeName))
         {
            TypeDictionary.Add(typeName, type);
         }

         return type;
      }
   }

   /// <summary>
   /// Class CustomXmlTextWriter.
   /// </summary>
   /// <remarks>Object data</remarks>
   public class CustomXmlTextWriter : XmlTextWriter
   {
      /// <summary>
      /// Initializes a new instance of the <see cref="CustomXmlTextWriter"/> class.
      /// </summary>
      /// <param name="stream">The stream.</param>
      /// <remarks>Object data</remarks>
      public CustomXmlTextWriter(Stream stream)
         : base(stream, null)
      {
      }

      /// <summary>
      /// Writes the specified start tag and associates it with the given namespace and prefix.
      /// </summary>
      /// <param name="prefix">The namespace prefix of the element.</param>
      /// <param name="localName">The local name of the element.</param>
      /// <param name="ns">The namespace URI to associate with the element. If this namespace is already in scope and has an associated prefix then the writer automatically writes that prefix also.</param>
      /// <remarks>Object data</remarks>
      public override void WriteStartElement(string prefix, string localName, string ns)
      {
         base.WriteStartElement(null, localName, string.Empty);
      }
   }
}