|
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.
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.
![]() |
|
Run the project.
The following is a sample output using default values.
The following are sample outputs when run at the command prompt.