[Mono-list] Serializable object with Non-Serializable Fields --> SerializationException

Jacek Rużyczka stacheldraht at interia.pl
Wed Jun 2 07:51:25 EDT 2010


Hi folks,

for my .NET remoting app, I am developing a class, which is gonna fetch some 
data from an RDBMS (by using DataSet objects) and make a report out of it. Of 
course, the class needs to be serializable, so it carries the [Serializable] 
attribute.

But: For the database access, it needs to use ADO.NET classes like 
IDataAdapter and DataSet...and these classes are NOT serializable. As you can 
see from my source-code (DBConnectionHandler is a home-brewn (serializable) 
class doing the database connection work for me), the corresponding variables 
are defined within the Start() method, so that they are no instance fields.

This is my source code:

using System;
using System.Collections;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Runtime.Serialization;
using System.Text;
using Npgsql;
using iwawi.batchjobs;

namespace iwawi.batchjobs.server
{

	/// <summary>
	/// This batch job generates a receipt (except payment reminder, which is 
done by
	/// PrintPaymentReminder).
	/// </summary>
	[Serializable]
	public class PrintReceipt : MarshalByRefObject, IBatchJob
	{
		[NonSerialized]
		private DBConnectionHandler handler;
		private string              uri         = "";
		private string              description = "Beleg (ausgenommen Mahnung) 
erstellen";
		
		public PrintReceipt()
		{
			if (ServerInfo.isVerbose) Console.WriteLine
				(DateTime.Now.ToString() +  ": Serverobjekt PrintReceipt initialisiert.");
		}
		
		public string URI {
			get {
				return this.uri;
			}
			set {
				this.uri = value;
			}
		}
		
		public string Description {
			get {
				return this.description;
			}
		}
		
		public DBConnectionHandler BackendConnectionHandler {
			set {
				this.handler = value;
			}
		}
		
		public bool Delay {
			get {
				return true;
			}
		}
		
		public bool Repeat {
			get {
				return false;
			}
		}
		
		public bool Start (string startingParams)
		{
			string    paramString        = this.uri.Substring(this.uri.IndexOf ('?') + 
1);
			string [] parameters         = paramString.Split('&', '=');
			string    receiptIDList      = "";
			int       i                  =  1;

			if (ServerInfo.isVerbose) Console.WriteLine(DateTime.Now.ToString() + ": 
iwawi://batchjobs/" + this.URI +
			                                            " gestartet.");
			
			foreach (string x in parameters) {
				if (i % 2 == 1 && x == "receipt_id_list") {
					receiptIDList = "ARRAY [" + x + "]";
				}
				
				i++;
			}
			
			if (receiptIDList.Length == 0) {
				this.CallingBack(this, new CallBackArgs(false, "Pflicht-Parameter 
receipt_id_list fehlt."));
				return false;
			}
			else {
				IDictionary args        = new Hashtable(1);
				IDictionary receiptData = new Hashtable();
				
				args.Add("receipt_id_array", receiptIDList);
				
				try {
					Skeleton headerSkel      = new Skeleton(108, this.handler);
					Skeleton boilerplateSkel = new Skeleton(107, this.handler);
					Skeleton contactDataSkel = new Skeleton(109, this.handler);
					Skeleton receiptSkel     = new Skeleton(110, this.handler);
					Skeleton lineItemSkel    = new Skeleton(111, this.handler);
					Skeleton printSkel       = new Skeleton(112, this.handler);
					
					IDbCommand cmd = this.handler.CreateCommand();
					cmd.CommandText = "SELECT separator FROM 
appdata.phone_number_separator;";
					args.Add("phone_number_separator", cmd.ExecuteScalar());
					
					IDataAdapter adapter = this.handler.CreateDataAdapter 
(receiptSkel.Process(args));
					DataSet dataSet = new DataSet("receipt_body");
					adapter.Fill(dataSet);
					DataRow row = dataSet.Tables [0].Rows [0];
					
					foreach (DataColumn col in dataSet.Tables [0].Columns) {
						receiptData.Add(col.ColumnName, row [col.ColumnName]);
						
						if (col.ColumnName == "receipt_language_id" || col.ColumnName == 
"clerk_person_id") {
							args.Add(col.ColumnName, row [col.ColumnName]);
						}
					}
					
					adapter = this.handler.CreateDataAdapter (headerSkel.Process(args));
					dataSet = new DataSet("receipt_header");
					adapter.Fill(dataSet);
					row = dataSet.Tables [0].Rows [0];
					
					foreach (DataColumn col in dataSet.Tables [0].Columns) {
						receiptData.Add(col.ColumnName, row [col.ColumnName]);
					}
					
					adapter = this.handler.CreateDataAdapter (boilerplateSkel.Process(args));
					dataSet = new DataSet("receipt_texts");
					adapter.Fill(dataSet);
					row = dataSet.Tables [0].Rows [0];
					
					foreach (DataColumn col in dataSet.Tables [0].Columns) {
						receiptData.Add(col.ColumnName, row [col.ColumnName]);
					}
					
					IDictionary contactData = new Hashtable();
					receiptData.Add("clerk_contact_data", contactData);
					adapter = this.handler.CreateDataAdapter (contactDataSkel.Process(args));
					dataSet = new DataSet("contact_data_header");
					adapter.Fill(dataSet);
					
					foreach (DataRow contactDataRow in dataSet.Tables [0].Rows) {
						contactData.Add(contactDataRow ["position_key"], contactDataRow 
["position_value"]);
					}
					
					IDictionary lineItemData = new Hashtable();
					receiptData.Add("line_items", lineItemData);
					adapter = this.handler.CreateDataAdapter (lineItemSkel.Process(args));
					dataSet = new DataSet("line_items");
					adapter.Fill(dataSet);
					int j = 0;

					foreach (DataRow lineItemRow in dataSet.Tables [0].Rows) {
						IDictionary lineItem = new Hashtable();
						lineItemData.Add(j, lineItem);
						
						foreach (DataColumn col in dataSet.Tables [0].Columns) {
							lineItem.Add(col.ColumnName, lineItemRow [col.ColumnName]);
						}
						
						j++;
					}
					
					adapter = null;
					return true;
				}
				catch (NpgsqlException ex) {
					string errorMessage = "Beleg konnte nicht erstellt werden. Ursache: \n" +
					                                        ex.Message + "\n\n" + 
ex.StackTrace;
					this.CallingBack(this, new CallBackArgs(false, errorMessage));

				if (ServerInfo.isVerbose) Console.WriteLine(DateTime.Now.ToString() + ": " 
+ errorMessage);

					return false;
				}
			}
		}
		
		public event BatchJob.CallBackHandler CallingBack;
	}
}


And when I start my app, this happens:

Marshaling pressed signal
Exception in Gtk# callback delegate
  Note: Applications can use GLib.ExceptionManager.UnhandledException to 
handle the exception.
System.Reflection.TargetInvocationException: Exception has been thrown by the 
target of an invocation. ---> 
System.Runtime.Serialization.SerializationException: Type 
Npgsql.NpgsqlDataReader in assembly Npgsql, Version=2.0.0.0, Culture=neutral, 
PublicKeyToken=5d8b90d52f46fda7 is not marked as serializable.  at 
System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke 
(System.Runtime.Remoting.Proxies.RealProxy rp, IMessage msg, System.Exception& 
exc, System.Object[]& out_args) [0x00000] in <filename unknown>:0 

What I don't really understand: Why are my ADO.NET objects *inside* the 
Start() method serialized? And: How do I make Mono keeps its hands off these 
objects when serializing? The attribute [NonSerialized] only applies to 
instance fields...

Thank you for any useful hints.

Regards
Jacek Rużyczka

----------------------------------------------------------------------
Sprawdz, co masz zapisane w swoich dloniach!
>>> http://linkint.pl/f2713



More information about the Mono-list mailing list