ObjectStateFormatter.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / xsp / System / Web / UI / ObjectStateFormatter.cs / 1 / ObjectStateFormatter.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Web.UI { 
 
    using System;
    using System.Collections; 
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Drawing; 
    using System.IO;
    using System.Globalization; 
    using System.Reflection; 
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Formatters.Binary; 
    using System.Security;
    using System.Security.Permissions;
    using System.Text;
    using System.Web.Compilation; 
    using System.Web.Configuration;
    using System.Web.Util; 
    using System.Web.Management; 
    using System.Web.UI.WebControls;
 
    //


 
    /// 
    /// ObjectStateFormatter is designed to efficiently serialize arbitrary object graphs 
    /// that represent the state of an object (decomposed into simpler types) into 
    /// a highly compact binary or ASCII representations.
    /// The formatter contains native support for optimized serialization of a fixed 
    /// set of known types such as ints, shorts, booleans, strings, other primitive types
    /// arrays, Pairs, Triplets, ArrayLists, Hashtables etc. In addition it utilizes
    /// TypeConverters for semi-optimized serialization of custom types. Finally, it uses
    /// binary serialization as a fallback mechanism. The formatter is also able to compress 
    /// IndexedStrings contained in the object graph.
    ///  
    [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)] 
    public sealed class ObjectStateFormatter : IStateFormatter, IFormatter {
 
        // Optimized type tokens
        private const byte Token_Int16 = 1;
        private const byte Token_Int32 = 2;
        private const byte Token_Byte = 3; 
        private const byte Token_Char = 4;
        private const byte Token_String = 5; 
        private const byte Token_DateTime = 6; 
        private const byte Token_Double = 7;
        private const byte Token_Single = 8; 
        private const byte Token_Color = 9;
        private const byte Token_KnownColor = 10;
        private const byte Token_IntEnum = 11;
        private const byte Token_EmptyColor = 12; 
        private const byte Token_Pair = 15;
        private const byte Token_Triplet = 16; 
        private const byte Token_Array = 20; 
        private const byte Token_StringArray = 21;
        private const byte Token_ArrayList = 22; 
        private const byte Token_Hashtable = 23;
        private const byte Token_HybridDictionary = 24;
        private const byte Token_Type = 25;
        private const byte Token_Nullable = 26; 
        private const byte Token_Unit = 27;
        private const byte Token_EmptyUnit = 28; 
 
        // String-table optimized strings
        private const byte Token_IndexedStringAdd = 30; 
        private const byte Token_IndexedString = 31;

        // Semi-optimized (TypeConverter-based)
        private const byte Token_StringFormatted = 40; 

        // Semi-optimized (Types) 
        private const byte Token_TypeRefAdd = 41; 
        private const byte Token_TypeRefAddLocal = 42;
        private const byte Token_TypeRef = 43; 

        // Un-optimized (Binary serialized) types
        private const byte Token_BinarySerialized = 50;
 
        // Optimized for sparse arrays
        private const byte Token_SparseArray = 60; 
 
        // Constant values
        private const byte Token_Null = 100; 
        private const byte Token_EmptyString = 101;
        private const byte Token_ZeroInt32 = 102;
        private const byte Token_True = 103;
        private const byte Token_False = 104; 

        // Known types for which we generate short type references 
        // rather than assembly qualified names 
        //
 

        private static readonly Type[] KnownTypes =
            new Type[] {
                typeof(object), 
                typeof(int),
                typeof(string), 
                typeof(bool) 
            };
 
        private static readonly Stack _streams = new Stack();

        // Format and Version
        private const byte Marker_Format = 0xFF; 
        private const byte Marker_Version_1 = 0x01;
 
        // The size of the string table. At most it can be Byte.MaxValue. 
        //
        private const int StringTableSize = Byte.MaxValue; 

        // Used during serialization
        private IDictionary _typeTable;
        private IDictionary _stringTable; 

        // Used during deserialization 
        private IList _typeList; 

        // Used during both serialization and deserialization 
        private int _stringTableCount;
        private string[] _stringList;

        // Used for performing Mac-encoding when this LosSerializer is used 
        // in view state serialization.
        private byte[] _macKeyBytes; 
 
        // If true, this class will throw an exception if it cannot deserialize a type or value.
        // If false, this class will use insert "null" if it cannot deserialize a type or value. 
        // Default is true, WebParts Personalization sets this to false.
        private bool _throwOnErrorDeserializing;

        // We use page to determine whether to to encrypt or decrypt based on Page.RequiresViewStateEncryptionInternal or Page.ContainsEncryptedViewstate 
        private Page _page;
 
        ///  
        /// Initializes a new instance of the ObjectStateFormatter.
        ///  
        public ObjectStateFormatter() : this(null) {
        }

        ///  
        /// 
        /// Initializes a new instance of the ObjectStateFormatter. A MAC encoding 
        /// key can be specified to have the serialized data encoded for view state 
        /// purposes.
        /// NOTE: this constructor is mainly for LOSFormatter's consumption, not used internally 
        /// 
        internal ObjectStateFormatter(byte[] macEncodingKey) : this(null, true) {
            _macKeyBytes = macEncodingKey;
        } 

        ///  
        ///  
        /// Initializes a new instance of the ObjectStateFormatter. A MAC encoding
        /// key can be specified to have the serialized data encoded for view state 
        /// purposes. The Page object is used to determine whether the viewstate will be encrypted
        /// for serialize and deserialize.
        /// 
 
        internal ObjectStateFormatter(Page page, bool throwOnErrorDeserializing) {
            _page = page; 
            _throwOnErrorDeserializing = throwOnErrorDeserializing; 
        }
 
        // This will return the MacKeyModifier provided in the LOSFormatter constructor or
        // generate one from Page if EnableViewStateMac is true.
        private byte[] GetMacKeyModifier() {
            if (_macKeyBytes == null) { 
                // Only generate a MacKeyModifier if we have a page
                if (_page == null) { 
                    return null; 
                }
 
                // Note: duplicated in MobilePage.cs, keep in sync

                // Use the page's directory and class name as part of the key (ASURT 64044)
                // We need to make sure that the hash is case insensitive, since the file system 
                // is, and strange view state errors could otherwise happen (ASURT 128657)
                int pageHashCode = StringComparer.InvariantCultureIgnoreCase.GetHashCode( 
                    _page.TemplateSourceDirectory); 
                pageHashCode += StringComparer.InvariantCultureIgnoreCase.GetHashCode(_page.GetType().Name);
 
                string viewStateUserKey = _page.ViewStateUserKey;
                if (viewStateUserKey != null) {
                    // Modify the key with the ViewStateUserKey, if any (ASURT 126375)
                    int count = Encoding.Unicode.GetByteCount(viewStateUserKey); 
                    _macKeyBytes = new byte[count + 4];
                    Encoding.Unicode.GetBytes(viewStateUserKey, 0, viewStateUserKey.Length, _macKeyBytes, 4); 
 
                }
                else { 
                    _macKeyBytes = new byte[4];
                }

                _macKeyBytes[0] = (byte)pageHashCode; 
                _macKeyBytes[1] = (byte)(pageHashCode >> 8);
                _macKeyBytes[2] = (byte)(pageHashCode >> 16); 
                _macKeyBytes[3] = (byte)(pageHashCode >> 24); 
            }
            return _macKeyBytes; 
        }

        /// 
        /// Adds a string reference during the deserialization process 
        /// to support deserialization of IndexedStrings.
        /// The string is added to the string list on the fly, so it is available 
        /// for future reference by index. 
        /// 
        private void AddDeserializationStringReference(string s) { 
            Debug.Assert((s != null) && (s.Length != 0));

            if (_stringTableCount == StringTableSize) {
                // loop around to the start of the table 
                _stringTableCount = 0;
            } 
 
            _stringList[_stringTableCount] = s;
            _stringTableCount++; 
        }

        /// 
        /// Adds a type reference during the deserialization process, 
        /// so that it can be referred to later by its index.
        ///  
        private void AddDeserializationTypeReference(Type type) { 
            // Type may be null, if there is no longer a Type on the system with the saved type name.
            // This is unlikely to happen with a Type stored in ViewState, but more likely with a Type 
            // stored in Personalization.
            _typeList.Add(type);
        }
 
        /// 
        /// Adds a string reference during the serialization process to support 
        /// the serialization of IndexedStrings. 
        /// The string is added to the string list, as well as to a string table
        /// for quick lookup. 
        /// 
        private void AddSerializationStringReference(string s) {
            Debug.Assert((s != null) && (s.Length != 0));
 
            if (_stringTableCount == StringTableSize) {
                // loop around to the start of the table 
                _stringTableCount = 0; 
            }
 
            string oldString = _stringList[_stringTableCount];
            if (oldString != null) {
                // it means we're looping around, and the existing table entry
                // needs to be removed, as a new one will replace it 
                Debug.Assert(_stringTable.Contains(oldString));
                _stringTable.Remove(oldString); 
            } 

            _stringTable[s] = _stringTableCount; 
            _stringList[_stringTableCount] = s;
            _stringTableCount++;
        }
 
        /// 
        /// Adds a type reference during the serialization process, so it 
        /// can be later referred to by its index. 
        /// 
        private void AddSerializationTypeReference(Type type) { 
            Debug.Assert(type != null);

            int typeID = _typeTable.Count;
            _typeTable[type] = typeID; 
        }
 
        // MethodInfo for Nullable.FromObject() 
        private static MethodInfo NullableFromObject = typeof(Nullable).GetMethod("FromObject");
        private static object BuildNullableObject(object value, Type type) { 
            // Convert from valuetype stored in value to Nullable
            // by calling Nullable.FromObject()
            Debug.Assert(type.IsValueType, "Expected type parameter in Nullable to be a value type");
            // 
            MethodInfo boundNullableFromObject = NullableFromObject.MakeGenericMethod(type);
            return boundNullableFromObject.Invoke(null, new object[] { value }); 
        } 

        [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.SerializationFormatter)] 
        internal object DeserializeWithAssert(Stream inputStream) {
            return Deserialize(inputStream);
        }
 
        /// 
        /// Deserializes an object graph from its binary serialized form 
        /// contained in the specified stream. 
        /// 
        public object Deserialize(Stream inputStream) { 
            if (inputStream == null) {
                throw new ArgumentNullException("inputStream");
            }
 
            Exception deserializationException = null;
 
            InitializeDeserializer(); 

            SerializerBinaryReader reader = new SerializerBinaryReader(inputStream); 
            try {
                byte formatMarker = reader.ReadByte();

                if (formatMarker == Marker_Format) { 
                    byte versionMarker = reader.ReadByte();
 
                    Debug.Assert(versionMarker == Marker_Version_1); 
                    if (versionMarker == Marker_Version_1) {
                        return DeserializeValue(reader); 
                    }
                }
            }
            catch (Exception e) { 
                deserializationException = e;
            } 
 
            // throw an exception if there was an exception during deserialization
            // or if deserialization was skipped because of invalid format or 
            // version data in the stream

            throw new ArgumentException(SR.GetString(SR.InvalidSerializedData), deserializationException);
        } 

 
        ///  
        /// Deserializes an object graph from its textual serialized form
        /// contained in the specified string. 
        /// 
        public object Deserialize(string inputString) {
            if (String.IsNullOrEmpty(inputString)) {
                throw new ArgumentNullException("inputString"); 
            }
 
            byte[] inputBytes = Convert.FromBase64String(inputString); 
            int length = inputBytes.Length;
 
#if !FEATURE_PAL // FEATURE_PAL does not enable cryptography
            try {
                if (_page != null && _page.ContainsEncryptedViewState) {
                    inputBytes = MachineKeySection.EncryptOrDecryptData(false, inputBytes, GetMacKeyModifier(), 0, length); 
                    length = inputBytes.Length;
                } 
                // We need to decode if the page has EnableViewStateMac or we got passed in some mac key string 
                else if ((_page != null && _page.EnableViewStateMac) || _macKeyBytes != null) {
                    inputBytes = MachineKeySection.GetDecodedData(inputBytes, GetMacKeyModifier(), 0, length, ref length); 
                }
            }
            catch (Exception e) {
                PerfCounters.IncrementCounter(AppPerfCounter.VIEWSTATE_MAC_FAIL); 
                ViewStateException.ThrowMacValidationError(e, inputString);
            } 
#endif // !FEATURE_PAL 
            object result = null;
            MemoryStream objectStream = GetMemoryStream(); 
            try {
                objectStream.Write(inputBytes, 0, length);
                objectStream.Position = 0;
                result = Deserialize(objectStream); 
            }
            finally { 
                ReleaseMemoryStream(objectStream); 
            }
            return result; 
        }

        /// 
        /// Deserializes an IndexedString. An IndexedString can either be the string itself (the 
        /// first occurrence), or a reference to it by index into the string table.
        ///  
        private IndexedString DeserializeIndexedString(SerializerBinaryReader reader, byte token) { 
            Debug.Assert((token == Token_IndexedStringAdd) || (token == Token_IndexedString));
 
            if (token == Token_IndexedString) {
                // reference to string in the current string table
                int tableIndex = (int)reader.ReadByte();
 
                Debug.Assert(_stringList[tableIndex] != null);
                return new IndexedString(_stringList[tableIndex]); 
            } 
            else {
                // first occurrence of this indexed string. Read in the string, and add 
                // a reference to it, so future references can be resolved.
                string s = reader.ReadString();

                AddDeserializationStringReference(s); 
                return new IndexedString(s);
            } 
        } 

        ///  
        /// Deserializes a Type. A Type can either be its name (the first occurrence),
        /// or a reference to it by index into the type table.  If we cannot load the type,
        /// we throw an exception if _throwOnErrorDeserializing is true, and we return null if
        /// _throwOnErrorDeserializing is false. 
        /// 
        private Type DeserializeType(SerializerBinaryReader reader) { 
            byte token = reader.ReadByte(); 
            Debug.Assert((token == Token_TypeRef) ||
                         (token == Token_TypeRefAdd) || 
                         (token == Token_TypeRefAddLocal));

            if (token == Token_TypeRef) {
                // reference by index into type table 
                int typeID = reader.ReadEncodedInt32();
                return (Type)_typeList[typeID]; 
            } 
            else {
                // first occurrence of this type. Read in the type, resolve it, and 
                // add it to the type table
                string typeName = reader.ReadString();

                Type resolvedType = null; 
                try {
                    if (token == Token_TypeRefAddLocal) { 
                        resolvedType = HttpContext.SystemWebAssembly.GetType(typeName, true); 
                    }
                    else { 
                        resolvedType = Type.GetType(typeName, true);
                    }
                }
                catch (Exception exception) { 
                    if (_throwOnErrorDeserializing) {
                        throw; 
                    } 
                    else {
                        // Log error message 
                        WebBaseEvent.RaiseSystemEvent(
                            SR.GetString(SR.Webevent_msg_OSF_Deserialization_Type, typeName),
                            this,
                            WebEventCodes.WebErrorObjectStateFormatterDeserializationError, 
                            WebEventCodes.UndefinedEventDetailCode,
                            exception); 
                    } 
                }
 
                AddDeserializationTypeReference(resolvedType);
                return resolvedType;
            }
        } 

        ///  
        /// Deserializes a single value from the underlying stream. 
        /// Essentially a token is read, followed by as much data needed to recreate
        /// the single value. 
        /// 
        private object DeserializeValue(SerializerBinaryReader reader) {
            byte token = reader.ReadByte();
 
            // NOTE: Preserve the order here with the order of the logic in
            //       the SerializeValue method. 
 
            switch (token) {
                case Token_Null: 
                    return null;
                case Token_EmptyString:
                    return String.Empty;
                case Token_String: 
                    return reader.ReadString();
                case Token_ZeroInt32: 
                    return 0; 
                case Token_Int32:
                    return reader.ReadEncodedInt32(); 
                case Token_Pair:
                    return new Pair(DeserializeValue(reader),
                                    DeserializeValue(reader));
                case Token_Triplet: 
                    return new Triplet(DeserializeValue(reader),
                                       DeserializeValue(reader), 
                                       DeserializeValue(reader)); 
                case Token_IndexedString:
                case Token_IndexedStringAdd: 
                    return DeserializeIndexedString(reader, token);
                case Token_ArrayList:
                    {
                        int count = reader.ReadEncodedInt32(); 
                        ArrayList list = new ArrayList(count);
                        for (int i = 0; i < count; i++) { 
                            list.Add(DeserializeValue(reader)); 
                        }
 
                        return list;
                    }
                case Token_True:
                    return true; 
                case Token_False:
                    return false; 
                case Token_Byte: 
                    return reader.ReadByte();
                case Token_Char: 
                    return reader.ReadChar();
                case Token_DateTime:
                    return DateTime.FromBinary(reader.ReadInt64());
                case Token_Double: 
                    return reader.ReadDouble();
                case Token_Int16: 
                    return reader.ReadInt16(); 
                case Token_Single:
                    return reader.ReadSingle(); 
                case Token_Hashtable:
                case Token_HybridDictionary:
                    {
                        int count = reader.ReadEncodedInt32(); 

                        IDictionary table; 
                        if (token == Token_Hashtable) { 
                            table = new Hashtable(count);
                        } 
                        else {
                            table = new HybridDictionary(count);
                        }
                        for (int i = 0; i < count; i++) { 
                            table.Add(DeserializeValue(reader),
                                      DeserializeValue(reader)); 
                        } 

                        return table; 
                    }
                case Token_Type:
                    return DeserializeType(reader);
                case Token_StringArray: 
                    {
                        int count = reader.ReadEncodedInt32(); 
 
                        string[] array = new string[count];
                        for (int i = 0; i < count; i++) { 
                            array[i] = reader.ReadString();
                        }

                        return array; 
                    }
                case Token_Array: 
                    { 
                        Type elementType = DeserializeType(reader);
                        int count = reader.ReadEncodedInt32(); 

                        Array list = Array.CreateInstance(elementType, count);
                        for (int i = 0; i < count; i++) {
                            list.SetValue(DeserializeValue(reader), i); 
                        }
 
                        return list; 
                    }
                case Token_IntEnum: 
                    {
                        Type enumType = DeserializeType(reader);
                        int enumValue = reader.ReadEncodedInt32();
 
                        return Enum.ToObject(enumType, enumValue);
                    } 
                case Token_Color: 
                    return Color.FromArgb(reader.ReadInt32());
                case Token_EmptyColor: 
                    return Color.Empty;
                case Token_KnownColor:
                    return Color.FromKnownColor((KnownColor)reader.ReadEncodedInt32());
                case Token_Unit: 
                    return new Unit(reader.ReadDouble(), (UnitType)reader.ReadInt32());
                case Token_EmptyUnit: 
                    return Unit.Empty; 
                case Token_SparseArray:
                    { 
                        Type elementType = DeserializeType(reader);
                        int count = reader.ReadEncodedInt32();
                        int itemCount = reader.ReadEncodedInt32();
 
                        // Guard against bad data
                        if (itemCount > count) { 
                            throw new InvalidOperationException(SR.GetString(SR.InvalidSerializedData)); 
                        }
 
                        Array list = Array.CreateInstance(elementType, count);
                        for (int i = 0; i < itemCount; ++i) {
                            // Data is encoded as 
                            int nextPos = reader.ReadEncodedInt32(); 

                            // Guard against bad data (nextPos way too big, or nextPos not increasing) 
                            if (nextPos >= count || nextPos < 0) { 
                                throw new InvalidOperationException(SR.GetString(SR.InvalidSerializedData));
                            } 
                            list.SetValue(DeserializeValue(reader), nextPos);
                        }

                        return list; 
                    }
                case Token_Nullable: 
                    Type T = DeserializeType(reader); 
                    object value = DeserializeValue(reader);
                    return BuildNullableObject(value, T); 
                case Token_StringFormatted:
                    {
                        object result = null;
 
                        Type valueType = DeserializeType(reader);
                        string formattedValue = reader.ReadString(); 
 
                        if (valueType != null) {
                            TypeConverter converter = TypeDescriptor.GetConverter(valueType); 
                            // TypeDescriptor.GetConverter() will never return null.  The ref docs
                            // for this method are incorrect.
                            try {
                                result = converter.ConvertFromInvariantString(formattedValue); 
                            }
                            catch (Exception exception) { 
                                if (_throwOnErrorDeserializing) { 
                                    throw;
                                } 
                                else {
                                    WebBaseEvent.RaiseSystemEvent(
                                        SR.GetString(SR.Webevent_msg_OSF_Deserialization_String, valueType.AssemblyQualifiedName),
                                        this, 
                                        WebEventCodes.WebErrorObjectStateFormatterDeserializationError,
                                        WebEventCodes.UndefinedEventDetailCode, 
                                        exception); 
                                }
                            } 
                        }

                        return result;
                    } 
                case Token_BinarySerialized:
                    { 
                        int length = reader.ReadEncodedInt32(); 

                        byte[] buffer = new byte[length]; 
                        if (length != 0) {
                            reader.Read(buffer, 0, length);
                        }
 
                        object result = null;
                        MemoryStream ms = GetMemoryStream(); 
                        try { 
                            ms.Write(buffer, 0, length);
                            ms.Position = 0; 
                            IFormatter formatter = new BinaryFormatter();

                            result = formatter.Deserialize(ms);
                        } 
                        catch (Exception exception) {
                            if (_throwOnErrorDeserializing) { 
                                throw; 
                            }
                            else { 
                                WebBaseEvent.RaiseSystemEvent(
                                    SR.GetString(SR.Webevent_msg_OSF_Deserialization_Binary),
                                    this,
                                    WebEventCodes.WebErrorObjectStateFormatterDeserializationError, 
                                    WebEventCodes.UndefinedEventDetailCode,
                                    exception); 
                            } 
                        }
                        finally { 
                            ReleaseMemoryStream(ms);
                        }
                        return result;
                    } 
                default:
                    throw new InvalidOperationException(SR.GetString(SR.InvalidSerializedData)); 
            } 
        }
 
        /// 
        /// Retrieves a memory stream from the pool.
        /// 
        private static MemoryStream GetMemoryStream() { 
            MemoryStream stream = null;
            if (_streams.Count > 0) { 
                lock (_streams) { 
                    if (_streams.Count > 0) {
                        stream = (MemoryStream)_streams.Pop(); 
                    }
                }
            }
 
            if (stream == null) {
                stream = new MemoryStream(2048); 
            } 
            return stream;
        } 


        /// 
        /// Initializes this instance to perform deserialization. 
        /// 
        private void InitializeDeserializer() { 
            _typeList = new ArrayList(); 

            for (int i = 0; i < KnownTypes.Length; i++) { 
                AddDeserializationTypeReference(KnownTypes[i]);
            }

            _stringList = new string[Byte.MaxValue]; 
            _stringTableCount = 0;
        } 
 
        /// 
        /// Initializes this instance to perform serialization. 
        /// 
        private void InitializeSerializer() {
            _typeTable = new HybridDictionary();
 
            for (int i = 0; i < KnownTypes.Length; i++) {
                AddSerializationTypeReference(KnownTypes[i]); 
            } 

            _stringList = new string[Byte.MaxValue]; 
            _stringTable = new Hashtable();
            _stringTableCount = 0;
        }
 
        /// 
        /// Returns a memory stream back into the pool. 
        ///  
        private static void ReleaseMemoryStream(MemoryStream stream) {
            Debug.Assert(stream != null); 
            stream.Position = 0;
            stream.SetLength(0);
            lock (_streams) {
                _streams.Push(stream); 
            }
        } 
 
        /// 
        /// Serializes an object graph into a textual serialized form. 
        /// 
        public string Serialize(object stateGraph) {
            string result = null;
 
            MemoryStream ms = GetMemoryStream();
            try { 
                Serialize(ms, stateGraph); 
                ms.SetLength(ms.Position);
 
                byte[] buffer = ms.GetBuffer();
                int length = (int)ms.Length;

#if !FEATURE_PAL // FEATURE_PAL does not enable cryptography 
                // We only support serialization of encrypted or encoded data through our internal Page constructors
                if (_page != null && _page.RequiresViewStateEncryptionInternal) { 
                    buffer = MachineKeySection.EncryptOrDecryptData(true, buffer, GetMacKeyModifier(), 0, length); 
                    length = buffer.Length;
                } 
                // We need to encode if the page has EnableViewStateMac or we got passed in some mac key string
                else if ((_page != null && _page.EnableViewStateMac) || _macKeyBytes != null) {
                    buffer = MachineKeySection.GetEncodedData(buffer, GetMacKeyModifier(), 0, ref length);
                } 

#endif // !FEATURE_PAL 
                result = Convert.ToBase64String(buffer, 0, length); 
            }
            finally { 
                ReleaseMemoryStream(ms);
            }
            return result;
        } 

        [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.SerializationFormatter)] 
        internal void SerializeWithAssert(Stream outputStream, object stateGraph) { 
            Serialize(outputStream, stateGraph);
        } 

        /// 
        /// Serializes an object graph into a binary serialized form within
        /// the specified stream. 
        /// 
        public void Serialize(Stream outputStream, object stateGraph) { 
            if (outputStream == null) { 
                throw new ArgumentNullException("outputStream");
            } 

            InitializeSerializer();

            SerializerBinaryWriter writer = new SerializerBinaryWriter(outputStream); 
            writer.Write(Marker_Format);
            writer.Write(Marker_Version_1); 
            SerializeValue(writer, stateGraph); 
        }
 
        /// 
        /// Serializes an IndexedString. If this is the first occurrence, it is written
        /// out to the underlying stream, and is added to the string table for future
        /// reference. Otherwise, a reference by index is written out. 
        /// 
        private void SerializeIndexedString(SerializerBinaryWriter writer, string s) { 
            object id = _stringTable[s]; 
            if (id != null) {
                writer.Write(Token_IndexedString); 
                writer.Write((byte)(int)id);
                return;
            }
 
            AddSerializationStringReference(s);
 
            writer.Write(Token_IndexedStringAdd); 
            writer.Write(s);
        } 

        /// 
        /// Serializes a Type. If this is the first occurrence, the type name is written
        /// out to the underlying stream, and the type is added to the string table for future 
        /// reference. Otherwise, a reference by index is written out.
        ///  
        private void SerializeType(SerializerBinaryWriter writer, Type type) { 
            object id = _typeTable[type];
            if (id != null) { 
                writer.Write(Token_TypeRef);
                writer.WriteEncoded((int)id);
                return;
            } 

            AddSerializationTypeReference(type); 
 
            if (type.Assembly == HttpContext.SystemWebAssembly) {
                writer.Write(Token_TypeRefAddLocal); 
                writer.Write(type.FullName);
            }
            else {
                writer.Write(Token_TypeRefAdd); 
                writer.Write(type.AssemblyQualifiedName);
            } 
        } 

        ///  
        /// Serializes a single value using the specified writer.
        /// Handles exceptions to provide more information about the value being serialized.
        /// 
        private void SerializeValue(SerializerBinaryWriter writer, object value) { 
            try {
 
                Stack objectStack = new Stack(); 
                objectStack.Push(value);
 
                do {
                    value = objectStack.Pop();

                    if (value == null) { 
                        writer.Write(Token_Null);
                        continue; 
                    } 

                    // NOTE: These are ordered roughly in the order of frequency. 

                    if (value is string) {
                        string s = (string)value;
                        if (s.Length == 0) { 
                            writer.Write(Token_EmptyString);
                        } 
                        else { 
                            writer.Write(Token_String);
                            writer.Write(s); 
                        }
                        continue;
                    }
 
                    if (value is int) {
                        int i = (int)value; 
                        if (i == 0) { 
                            writer.Write(Token_ZeroInt32);
                        } 
                        else {
                            writer.Write(Token_Int32);
                            writer.WriteEncoded(i);
                        } 
                        continue;
                    } 
 
                    if (value is Pair) {
                        writer.Write(Token_Pair); 

                        Pair p = (Pair)value;
                        objectStack.Push(p.Second);
                        objectStack.Push(p.First); 
                        continue;
                    } 
 
                    if (value is Triplet) {
                        writer.Write(Token_Triplet); 

                        Triplet t = (Triplet)value;
                        objectStack.Push(t.Third);
                        objectStack.Push(t.Second); 
                        objectStack.Push(t.First);
                        continue; 
                    } 

                    if (value is IndexedString) { 
                        Debug.Assert(((IndexedString)value).Value != null);
                        SerializeIndexedString(writer, ((IndexedString)value).Value);
                        continue;
                    } 

                    if (value.GetType() == typeof(ArrayList)) { 
                        writer.Write(Token_ArrayList); 

                        ArrayList list = (ArrayList)value; 

                        writer.WriteEncoded(list.Count);
                        for (int i = list.Count - 1; i >= 0; i--) {
                            objectStack.Push(list[i]); 
                        }
 
                        continue; 
                    }
 
                    if (value is bool) {
                        if (((bool)value)) {
                            writer.Write(Token_True);
                        } 
                        else {
                            writer.Write(Token_False); 
                        } 
                        continue;
                    } 
                    if (value is byte) {
                        writer.Write(Token_Byte);
                        writer.Write((byte)value);
                        continue; 
                    }
                    if (value is char) { 
                        writer.Write(Token_Char); 
                        writer.Write((char)value);
                        continue; 
                    }
                    if (value is DateTime) {
                        writer.Write(Token_DateTime);
                        writer.Write(((DateTime)value).ToBinary()); 
                        continue;
                    } 
                    if (value is double) { 
                        writer.Write(Token_Double);
                        writer.Write((double)value); 
                        continue;
                    }
                    if (value is short) {
                        writer.Write(Token_Int16); 
                        writer.Write((short)value);
                        continue; 
                    } 
                    if (value is float) {
                        writer.Write(Token_Single); 
                        writer.Write((float)value);
                        continue;
                    }
 
                    if (value is IDictionary) {
                        bool canSerializeDictionary = false; 
 
                        if (value.GetType() == typeof(Hashtable)) {
                            writer.Write(Token_Hashtable); 
                            canSerializeDictionary = true;
                        }
                        else if (value.GetType() == typeof(HybridDictionary)) {
                            writer.Write(Token_HybridDictionary); 
                            canSerializeDictionary = true;
                        } 
 
                        if (canSerializeDictionary) {
                            IDictionary table = (IDictionary)value; 

                            writer.WriteEncoded(table.Count);
                            if (table.Count != 0) {
                                foreach (DictionaryEntry entry in table) { 
                                    objectStack.Push(entry.Value);
                                    objectStack.Push(entry.Key); 
                                } 
                            }
 
                            continue;
                        }
                    }
 
                    if (value is Type) {
                        writer.Write(Token_Type); 
                        SerializeType(writer, (Type)value); 
                        continue;
                    } 

                    Type valueType = value.GetType();

                    if (value is Array) { 
                        // We only support Arrays with rank 1 (No multi dimensional arrays
                        if (((Array)value).Rank > 1) { 
                            continue; 
                        }
 
                        Type underlyingType = valueType.GetElementType();

                        if (underlyingType == typeof(string)) {
                            string[] strings = (string[])value; 
                            bool containsNulls = false;
                            for (int i = 0; i < strings.Length; i++) { 
                                if (strings[i] == null) { 
                                    // Will have to treat these as generic arrays since we
                                    // can't represent nulls in the binary stream, without 
                                    // writing out string token markers.
                                    // Generic array writing includes the token markers.
                                    containsNulls = true;
                                    break; 
                                }
                            } 
 
                            if (!containsNulls) {
                                writer.Write(Token_StringArray); 
                                writer.WriteEncoded(strings.Length);
                                for (int i = 0; i < strings.Length; i++) {
                                    writer.Write(strings[i]);
                                } 
                                continue;
                            } 
                        } 

                        Array values = (Array)value; 

                        // Optimize for sparse arrays, if the array is more than 3/4 nulls
                        if (values.Length > 3) {
                            int sparseThreshold = (values.Length / 4) + 1; 
                            int numValues = 0;
                            List items = new List(sparseThreshold); 
                            for (int i = 0; i < values.Length; ++i) { 
                                if (values.GetValue(i) != null) {
                                    ++numValues; 
                                    if (numValues >= sparseThreshold) {
                                        break;
                                    }
                                    items.Add(i); 
                                }
                            } 
 
                            // We have enough nulls to use sparse array format 
                            if (numValues < sparseThreshold) { 
                                writer.Write(Token_SparseArray);
                                SerializeType(writer, underlyingType);

                                writer.WriteEncoded(values.Length); 
                                writer.WriteEncoded(numValues);
 
                                // Now we need to just serialize pairs representing the index, and the item 
                                foreach (int index in items) {
                                    writer.WriteEncoded(index); 
                                    SerializeValue(writer, values.GetValue(index));
                                }

                                continue; 
                            }
                        } 
 
                        writer.Write(Token_Array);
                        SerializeType(writer, underlyingType); 

                        writer.WriteEncoded(values.Length);
                        for (int i = values.Length - 1; i >= 0; i--) {
                            objectStack.Push(values.GetValue(i)); 
                        }
 
                        continue; 
                    }
 
                    if (valueType.IsEnum) {
                        Type underlyingType = Enum.GetUnderlyingType(valueType);
                        if (underlyingType == typeof(int)) {
                            writer.Write(Token_IntEnum); 
                            SerializeType(writer, valueType);
                            writer.WriteEncoded((int)value); 
 
                            continue;
                        } 
                    }

                    if (valueType == typeof(Color)) {
                        Color c = (Color)value; 
                        if (c.IsEmpty) {
                            writer.Write(Token_EmptyColor); 
                            continue; 
                        }
                        if (!c.IsNamedColor) { 
                            writer.Write(Token_Color);
                            writer.Write(c.ToArgb());
                            continue;
                        } 
                        else {
                            writer.Write(Token_KnownColor); 
                            writer.WriteEncoded((int)c.ToKnownColor()); 
                            continue;
                        } 
                    }

                    if (value is Unit) {
                        Unit uval = (Unit)value; 
                        if (uval.IsEmpty) {
                            writer.Write(Token_EmptyUnit); 
                        } 
                        else {
                            writer.Write(Token_Unit); 
                            writer.Write(uval.Value);
                            writer.Write((int)uval.Type);
                        }
                        continue; 
                    }
 
                    // Handle the remaining types 
                    // First try to get a type converter, and then resort to
                    // binary serialization if all else fails 

                    TypeConverter converter = TypeDescriptor.GetConverter(valueType);
                    bool canConvert = System.Web.UI.Util.CanConvertToFrom(converter, typeof(string));
 
                    if (canConvert) {
                        writer.Write(Token_StringFormatted); 
                        SerializeType(writer, valueType); 
                        writer.Write(converter.ConvertToInvariantString(null, value));
                    } 
                    else {
                        IFormatter formatter = new BinaryFormatter();
                        MemoryStream ms = new MemoryStream(256);
                        formatter.Serialize(ms, value); 

                        byte[] buffer = ms.GetBuffer(); 
                        int length = (int)ms.Length; 

                        writer.Write(Token_BinarySerialized); 
                        writer.WriteEncoded(length);
                        if (buffer.Length != 0) {
                            writer.Write(buffer, 0, (int)length);
                        } 
                    }
                } 
                while (objectStack.Count > 0); 
            }
            catch (Exception serializationException) { 
                throw new ArgumentException(SR.GetString(SR.ErrorSerializingValue, value.ToString(), value.GetType().FullName),
                                            serializationException);
            }
        } 

        #region Implementation of IStateFormatter 
        object IStateFormatter.Deserialize(string serializedState) { 
            return Deserialize(serializedState);
        } 

        string IStateFormatter.Serialize(object state) {
            return Serialize(state);
        } 
        #endregion
 
        #region Implementation of IFormatter 

        ///  
        SerializationBinder IFormatter.Binder {
            get {
                return null;
            } 
            set {
            } 
        } 

 
        /// 
        StreamingContext IFormatter.Context {
            get {
                return new StreamingContext(StreamingContextStates.All); 
            }
            set { 
            } 
        }
 

        /// 
        ISurrogateSelector IFormatter.SurrogateSelector {
            get { 
                return null;
            } 
            set { 
            }
        } 


        /// 
        object IFormatter.Deserialize(Stream serializationStream) { 
            return Deserialize(serializationStream);
        } 
 

        ///  
        void IFormatter.Serialize(Stream serializationStream, object stateGraph) {
            Serialize(serializationStream, stateGraph);
        }
        #endregion 

        ///  
        /// Custom BinaryReader used during the deserialization. 
        /// 
        private sealed class SerializerBinaryReader : BinaryReader { 

            public SerializerBinaryReader(Stream stream) : base(stream) {
            }
 
            public int ReadEncodedInt32() {
                return Read7BitEncodedInt(); 
            } 
        }
 

        /// 
        /// Custom BinaryWriter used during the serialization.
        ///  
        private sealed class SerializerBinaryWriter : BinaryWriter {
 
            public SerializerBinaryWriter(Stream stream) : base(stream) { 
            }
 
            public void WriteEncoded(int value) {
                //

                uint v = (uint)value; 
                while (v >= 0x80) {
                    Write((byte)(v | 0x80)); 
                    v >>= 7; 
                }
                Write((byte)v); 
            }
        }
    }
}
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK