< Intro To Serialization | Main | C# Binary SOAP Program Example >

 


 

Chapter 4 Part 2:

Serialization

 

 

What do we have in this chapter 4 Part 2?

  1. C++ Binary SOAP Program Example

 

 

 

C++ Binary SOAP Program Example

 

Create a new CLR console application project and you might want to use BinarySOAPSimpleCP for the project and solution names as shown below.

 

C++ Binary SOAP Program Example - a new CLR console application project creation

 

Add the using directives. You may want to discard the comments. Be careful with the matching braces.

 

// BinarySOAPSimpleCP.cpp : main project file.

// This sample illustrates the different binary and SOAP serialization methods. This

// sample illustrates using the IFormatter interface along with the BinaryFormatter

// and the SoapFormatter (obsolete) classes. Additionally, this sample illustrates simple

// serialization as well as selective and custom serialization. The sample illustrates

// both serialization and deserialization from a file. Note however, a serialized

// file can only be deserialized using the same flags. That is if the custom flag

// "/custom" was specified during serialization, it must also be present when

// deserialized.

//

// Usage:

//      usage: executable_file_name [/file outfile.bin] [/soap | /binary] [/deserialize | /serialize]

//                        [/simple | /selective | /custom]

//      /file    filename        Filename to serialize to or deserialize from [default = binary.bin]

//      /soap                    Serialize data to SOAP format

//      /binary                  Serialize data to binary format [default]

//      /deserialize             Deserialize data from file

//      /serialize               Serialize data to file [default]

//      /simple                  Serialize a simple data structure

//      /selective               Serialize a selective data structure

//      /custom                  Serialize a custom data structure

//

// Sample usage:

//      Basic binary serialization:

//          executable_file_name /binary /serialize /simple /file simple.bin

//      Basic binary deserialization:

//          executable_file_name /binary /deserialize /simple /file simple.bin

//      Custom SOAP serialization:

//          executable_file_name /soap /serialize /selective /file selective.soap

//      Custom SOAP deserialization:

//          executable_file_name /soap /deserialize /selective /file selective.soap

 

#include "stdafx.h"

 

using namespace System;

using namespace System::Collections::Generic;

using namespace System::Text;

using namespace System::IO;

using namespace System::Runtime::Serialization;

using namespace System::Runtime::Serialization::Formatters::Binary;

// using System::Runtime::Serialization::Formatters::Soap; - obsolete before 3.5

// included in the ::Formatters::Binary directive

using namespace System::Net;

using namespace System::Net::Sockets;

 

 

Add the following classes and you may want to discard the comments.

 

    /// <summary>

    /// This is a simple class to illustrate binary serialization. It contains both

    /// public and private fields.

    /// </summary>

    [Serializable]

    ref class MyBasicData

    {

            public:

                        int IntField1;

                        String^ StringField1;

            private:

                        int IntField2;

 

        /// <summary>

        /// Constructor for MyBasicData that initializes member variables.

        /// </summary>

        public:

        MyBasicData()

        {

            IntField1 = 1066;

            StringField1 = "Basic Data Info";

            IntField2 = 1492;

        }

 

        /// <summary>

        /// Simple routine to display the values of each member variable.

        /// </summary>

        public:

        void Print()

        {

              Console::WriteLine("MyBasicData::IntField1    = {0}", IntField1);

              Console::WriteLine("MyBasicData::StringField1 = {0}", StringField1);

              Console::WriteLine("MyBasicData::IntField2    = {0}", IntField2);

         }

    };

 

    /// <summary>

    /// This class shows how to set the NonSerialized attribute on a class property

    /// such that it will not appear in the serialized output.

    /// </summary>

    [Serializable]

    ref class MySelectiveData

    {

            public:

                        int UserId;

                        String^ UserName;

 

            private:

                        [NonSerialized]

                        String^ Password;

 

        /// <summary>

        /// Constructor for MySelectiveData to initialize member variables.

        /// </summary>

            public:

                        MySelectiveData()

                        {

                              UserId = 100;

                              UserName = "Joe User";

                              Password = "DefaultPassword";

                          }

 

        /// <summary>

        /// Simple routine to display the contents of the MySelectiveData class

        /// </summary>

            public:

                        void Print()

                        {

                                    Console::WriteLine("MySelectiveData::UserId   = {0}", UserId);

                                    Console::WriteLine("MySelectiveData::UserName = {0}", UserName);

                                    Console::WriteLine("MySelectiveData::Password = {0}", Password);

                         }

 

        /// <summary>

        /// Method for setting the current password.

        /// </summary>

            public:

                        void SetPassword(String^ newpassword)

                        {

                              Password = newpassword;

                         }

    };

 

    /// <summary>

    /// This class shows how to customize the binary serialization process by implementing

    /// the ISerializable interface.

    /// </summary>

    [Serializable]

    ref class MyCustomData sealed : ISerializable

    {

            public:

                        int IntField1;

                        String^ StringField1;

       

            public:

                        [NonSerialized]

                        IPAddress^ LocalAddress;

 

        /// <summary>

        /// Constructor for MyCustomData that initialized the member variables.

        /// </summary>

            public:

                        MyCustomData()

                        {

                            IntField1 = 1069;

                            StringField1 = "ISerializable custom serialization";

                            LocalAddress = IPAddress::Parse("1.2.3.4");

                          }

 

        /// <summary>

        /// Simple print routine for displaying the member fields of the MyCustomData class.

        /// </summary>

            public:

                        void Print()

                        {

                                    Console::WriteLine("MyCustomData::IntField1    = {0}", IntField1);

                                    Console::WriteLine("MyCustomData::StringField1 = {0}", StringField1);

                                    Console::WriteLine("MyCustomData::LocalAddress = {0}", LocalAddress->ToString());

                         }

 

        /// <summary>

        /// Method called when the object is serialized. Each member property to be

        /// serialized is assigned as string key name. This will be used in the custom

        /// constructor to retrieve the value for each property when deserialization

        /// takes place

        /// </summary>

        /// <param name="info">

        /// Contains serialization context information for each property

        /// to be serialized.

        /// </param>

        /// <param name="context">

        /// Describes the source and destination of a given serialized stream

        /// </param>

            public:

                        [System::Security::Permissions::SecurityPermissionAttribute

                                              (System::Security::Permissions::SecurityAction::LinkDemand,

                                              Flags=System::Security::Permissions::SecurityPermissionFlag::SerializationFormatter)]

                        virtual void GetObjectData(SerializationInfo^ info, StreamingContext context)

                        {

                            info->AddValue("IntField1", IntField1);

                            info->AddValue("whatever", StringField1);

                         }

 

        /// <summary>

        /// Custom constructor that is called when the object is deserialized such that

        /// it can retrieve the values for properties by using the keys assigned to each.

        /// It can also initialize other properties as desired.

        /// </summary>

        /// <param name="info"></param>

        /// <param name="context"></param>

        protected:

        MyCustomData(SerializationInfo^ info, StreamingContext context)

        {

            IPHostEntry^ ipHost = nullptr;

 

            IntField1 = info->GetInt32("IntField1");

            StringField1 = info->GetString("whatever");

 

            // Since we don't retrieve the LocalAddress property (and since it wasn't

            // serialized to begin with, we find the local IP address and initialize it to that.

            try

            {

                ipHost = Dns::GetHostEntry("127.0.0.1");

                if (ipHost->AddressList->Length > 0)

                {

                       LocalAddress = ipHost->AddressList[0];

                }

                else

                {

                        LocalAddress = IPAddress::Loopback;

                }

            }

            catch (SocketException^)

            {

                   LocalAddress = IPAddress::Loopback;

            }

        }

    };

 

    /// <summary>

    /// Main class that contains the the Main routine for this sample.

    /// </summary>

    ref class BinarySerialization

    {

        /// <summary>

        /// Displays usage information for this sample.

        /// </summary>

        public:

        static void usage()

        {

            Environment::GetCommandLineArgs();

            Console::WriteLine("Usage: executable_file_name [/file outfile.bin] [/soap | /binary] [/deserialize | /serialize]");

            Console::WriteLine("                  [/simple | /selective | /custom]");

            Console::WriteLine("Available options:");

            Console::WriteLine("    /file    filename        Filename to serialize to or deserialize from [default = binary.bin]");

            Console::WriteLine("    /soap                    Serialize data to SOAP format");

            Console::WriteLine("    /binary                  Serialize data to binary format [default]");

            Console::WriteLine("    /deserialize             Deserialize data from file");

            Console::WriteLine("    /serialize               Serialize data to file [default]");

            Console::WriteLine("    /simple                  Serialize a simple data structure");

            Console::WriteLine("    /selective               Serialize a selective data structure");

            Console::WriteLine("    /custom                  Serialize a custom data structure");

            Console::WriteLine();

            Console::WriteLine("Sample usage:");

            Console::WriteLine("1. Basic binary serialization:");

            Console::WriteLine("     executable_file_name /binary /serialize /simple /file simple.bin");

            Console::WriteLine("2. Basic binary deserialization:");

            Console::WriteLine("     executable_file_name /binary /deserialize /simple /file simple.bin");

            Console::WriteLine("3. Custom SOAP serialization:");

            Console::WriteLine("     executable_file_name /soap /serialize /selective /file selective.soap");

            Console::WriteLine("4. Custom SOAP deserialization:");

            Console::WriteLine("     executable_file_name /soap /deserialize /selective /file selective.soap");

            Console::WriteLine("Else, default values will be used...");

        }

};

 

Next, add the enum classes.

 

    /// <summary>

    /// Simple enumeration for the different types of serialization supported.

    /// </summary>

    enum class SerializeType

    {

        useBinary, useSoap

    };

 

    /// <summary>

    /// Simple enumeration for the operation to perform: deserialization or serialization.

    /// </summary>

    enum class SerializeOperation

    {

        opRead, opWrite

    };

 

    /// <summary>

    /// Simple enumeration for the class type to serialize or deserialize.

    /// </summary>

    enum class SerializeDataType

    {

        typeSimple, typeSelective, typeCustom

    };

 

Finally, add the main() code.

 

/// <summary>

/// Main function which parses the command line, creates the data to

/// serialize, creates the file stream, and either serializes or

/// deserializes the data. If deserialization is chosen, the member

/// fields of the deserialized class are printed to the console.

/// </summary>

/// <param name="args">Command line arguments passed to program.</param>

int main(array<System::String ^> ^args)

{

            Stream^ fileStream;

            IFormatter^ myFormatter = nullptr;

            // Default file name...

            String^ fileName = L"binary.bin";

            SerializeType serializationType = SerializeType::useBinary;

            SerializeOperation serializeOp = SerializeOperation::opWrite;

            SerializeDataType dataType = SerializeDataType::typeSimple;

 

            Environment::GetCommandLineArgs();

 

                        // Parse the command line, 0 = executable_file_name

                        for (int i = 0; i < args->Length; i++)

                        {

                                    if (String::Compare(args[i], L"/file", true) == 0)

                                    {

                                                try

                                                {

                                                            fileName = args[++i];

                                                }

                                                catch (IndexOutOfRangeException^ err)

                                                {

                                                            Console::WriteLine(L"Please specify output filename!\n");

                                                            Console::WriteLine(err->Message);

                                                }

                                    }

                                    else if (String::Compare(args[i], L"/binary", true) == 0)

                                    {

                                                serializationType = SerializeType::useBinary;

                                    }

                                    else if (String::Compare(args[i], L"/soap", true) == 0)

                                    {

                                                serializationType = SerializeType::useSoap;

                                    }

                                    else if (String::Compare(args[i], L"/deserialize", true) == 0)

                                    {

                                                serializeOp = SerializeOperation::opRead;

                                    }

                                    else if (String::Compare(args[i], L"/serialize", true) == 0)

                                    {

                                                serializeOp = SerializeOperation::opWrite;

                                    }

                                    else if (String::Compare(args[i], L"/simple", true) == 0)

                                    {

                                                dataType = SerializeDataType::typeSimple;

                                    }

                                    else if (String::Compare(args[i], L"/selective", true) == 0)

                                    {

                                                dataType = SerializeDataType::typeSelective;

                                    }

                                    else if (String::Compare(args[i], L"/custom", true) == 0)

                                    {

                                                dataType = SerializeDataType::typeCustom;

                                    }

                                    else

                                    {

                                                Console::WriteLine(L"No or wrong argument(s) found!");

                                                BinarySerialization::usage();

                                                return 0;

                                    }

                        }

 

    // Create the appropriate file stream - to write to or read from.

    if (serializeOp == SerializeOperation::opWrite)

    {

        fileStream = gcnew FileStream(

                fileName,

                FileMode::Create,

                FileAccess::Write,

                FileShare::None

                );

    }

    else

    {

        fileStream = gcnew FileStream(

                fileName,

                FileMode::Open,

                FileAccess::Read,

                FileShare::None

                );

    }

 

    // Create the formatter - binary or SOAP, this should be redundant...

    if ((serializationType == SerializeType::useBinary) || (serializationType == SerializeType::useSoap))

    {

        myFormatter = gcnew BinaryFormatter();

    }

 

    // Perform the selected operation: read or write

    if (serializeOp == SerializeOperation::opWrite)

    {

        // Create an instance of the selected class and serialized it to the file stream

        if (dataType == SerializeDataType::typeSimple)

        {

            MyBasicData^ basicData = nullptr;

            basicData = gcnew MyBasicData();

 

            // Set field to something other than the constructor default value

            basicData->IntField1 = 999;

            Console::WriteLine(L"Simple data being serialized:");

            basicData->Print();

 

            // Serialize the data to the stream

            try

            {

                myFormatter->Serialize(fileStream, basicData);

            }

            catch (SerializationException^ err)

            {

                Console::WriteLine(L"Simple serialization failed: " + err->Message);

            }

        }

        else if (dataType == SerializeDataType::typeSelective)

        {

            MySelectiveData^ selectiveData = nullptr;

            selectiveData = gcnew MySelectiveData();

            // Set field to something other than the constructor default value

            selectiveData->SetPassword(L"abcd1234");

            Console::WriteLine(L"Selective data being serialized:");

            selectiveData->Print();

 

            // Serialize the date to the stream

            try

            {

                myFormatter->Serialize(fileStream, selectiveData);

            }

            catch (SerializationException^ err)

            {

                 Console::WriteLine(L"Selective serialization failed: " + err->Message);

            }

        }

        else

        {

            MyCustomData^ customData = nullptr;

            customData = gcnew MyCustomData();

            // Set field to something other than the constructor default value

            customData->IntField1 = 888;

            Console::WriteLine(L"Custom data being serialized:");

            customData->Print();

 

            try

            {

                myFormatter->Serialize(fileStream, customData);

            }

            catch (SerializationException^ err)

            {

                 Console::WriteLine(L"Custom serialization failed: " + err->Message);

            }

        }

    }

    else

    {

        // Deserialize the selected class from the file stream

        if (dataType == SerializeDataType::typeSimple)

        {

            MyBasicData^ basicData = nullptr;

 

            try

            {

                basicData = (MyBasicData^)myFormatter->Deserialize(fileStream);

                Console::WriteLine(L"Simple data being deserialized:");

                basicData->Print();

            }

            catch (SerializationException^ err)

            {

                 Console::WriteLine(L"Deserialization failed: " + err->Message);

            }

        }

        else if (dataType == SerializeDataType::typeSelective)

        {

            MySelectiveData^ selectiveData = nullptr;

 

            try

            {

                selectiveData = (MySelectiveData^)myFormatter->Deserialize(fileStream);

                Console::WriteLine(L"Selective data being deserialized:");

                selectiveData->Print();

            }

            catch (SerializationException^ err)

            {

                 Console::WriteLine(L"Deserialization failed: " + err->Message);

            }

        }

        else

        {

            MyCustomData^ customData = nullptr;

 

            try

            {

                customData = (MyCustomData^)myFormatter->Deserialize(fileStream);

                Console::WriteLine(L"Custom data being deserialized:");

                customData->Print();

            }

            catch (SerializationException^ err)

            {

                 Console::WriteLine(L"Deserialization failed: " + err->Message);

            }

        }

    }

    fileStream->Close();

    return 0;

}

 

Build the project. Make sure there is no error.

 

C++ Binary SOAP Program Example - building the project  

 

Run the project.

 

C++ Binary SOAP Program Example - running the project without debugging

 

The following is a sample output using default values.

 

C++ Binary SOAP Program Example - a simple output using default argument values

 

The following are sample outputs when run at the command prompt.

 

C++ Binary SOAP Program Example - a sample output showing the options

 

C++ Binary SOAP Program Example - the sample outputs with different argument values

 

 

 


 

< Intro To Serialization | Main | C# Binary SOAP Program Example >