Solving the “XmlSerializer and ‘not expected’ Inherited Types” problem without implementing IXmlSerializable

2 October 2008

Last week I ran into the following exception when serializing an object into xml:

System.InvalidOperationException: There was an error generating the XML document. —>  System.InvalidOperationException: The type <Type> was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.

The business object I was trying to serialize had a similar construction like these classes:

public class FooParent
{
	public Foo MyFoo { get; set; }
	public List<Foo> MyFoos { get; set; }
}

public class Foo
{
	public int X { get; set; }
	public int Y { get; set; }
}

However the Foo members of the FooParent where not set with Foo objects, but with SqlFoo objects derived from Foo and with a class definition in a different assembly:

public class SqlFoo : Foo
{
	public SqlFoo() : this(0) {}

	public SqlFoo(int id)
	{
		this.ID = id;
	}

	public int ID { get; set; }
}

So, the next test example will throw the InvalidOperationException:

FooParent target = new FooParent();
target.MyFoo = new SqlFoo(1);
target.MyFoos = new List<Foo>(new SqlFoo[] { new SqlFoo(2) });

XmlSerializer serializer = new XmlSerializer(typeof(FooParent));
StringWriter writer = new StringWriter();
serializer.Serialize(writer, target);

After consulting my dear friend Dr. Google, I found a nice solution from Simon Hewitt. I really liked the usage of the implicit casting operators! But I didn’t like implementing the IXmlSerializable interface. There is too much thinking involved about XmlAttributeOverrides and XmlReader, and I wishes there would be a more intuitively solution.

Luckily I also had an Epiphany of my own!  I tried this Foo wrapper, which continues the idea of using the casting operators:

public class XmlFooWrapper
{
	private Foo model;

	public XmlFooWrapper() : this(new Foo()) {}

	public XmlFooWrapper(Foo model)
	{
		this.model = model;
	}

	public static implicit operator Foo(XmlFooWrapper wrapper)
	{
		return wrapper != null ? wrapper.model : null;
	}

	public static implicit operator XmlFooWrapper(Foo model)
	{
		return model!= null ? new XmlFooWrapper(model) : null;
	}

	public int X
	{
		get { return model.X; }
		set { model.X = value; }
	}

	public int Y
	{
		get { return model.Y; }
		set { model.Y = value; }
	}
}

The FooParent was altered by adding the [XmlElement(Type = typeof(XmlFooWrapper))] attribute to the MyFoo member. The List<> member was decorated with the [XmlArrayItem(ElementName=“Foo”, Type=typeof(XmlFooWrapper))] attribute:

public class FooParent
{
	[XmlElement(Type = typeof(XmlFooWrapper))]
	public Foo MyFoo { get; set; }

	[XmlArrayItem(ElementName = "Foo", Type = typeof(XmlFooWrapper))]
	public List<Foo> MyFoos { get; set; }
}

It worked! Running the test example again results in the following xml:

<FooParent>
  <MyFoo>
    <X>0</X>
    <Y>0</Y>
  </MyFoo>
  <MyFoos>
    <Foo>
      <X>0</X>
      <Y>0</Y>
    </Foo>
  </MyFoos>
</FooParent>

“Elfproef” algorithm in C# for the Dutch “Burgerservicenummer”

25 September 2008

In the Netherlands everyone has a unique personal number called “burgerservicenummer“.

It’s a 9 digit number that satisfies to an alternative on the so-called elfproef: if the burgerservicenummer is represented by ABCDEFGHI, then 9*A + 8*B + 7*C + 6*D + 5*E + 4*F + 3*G + 2*H + (-1*I) must be a multiple of 11.

The following is a fast integer-based algorithm in C# to validate a burgerservicenummer:

public static bool ValidateElfProef(int value)
{
	int divisor = 1000000000;
	int total = 0;
	int result = value;
	for (int i = 9; i > 1; i--)
		total += i * Math.DivRem(result, divisor /= 10, out result);

	int rest;
	Math.DivRem(total, 11, out rest);

	return result == rest;
}

public static bool ValidateElfProef(string value)
{
	return ValidateElfProef(Convert.ToInt32(value));
}

.NET style random generator with a normal or Gaussian distribution in C#

31 March 2008

Recently I was looking for a .NET style random generator with a normal or Gaussian distribution. I found a nice example on Koders.com, which usses the Box-Muller transformation, and build the algorithm into a class derived from System.Random. A mean of 0.5 and standard deviation of 1/2pi is used to keep the values returned by Sample() between 0 and 1. Values falling outside the range [ 0.0, 1.0 ) are replace by the next sample. It might not be perfect for scientific use, but it’s good enough to suit my needs.

public class RandomNormal : Random
{
	private double cache;
	private bool isCacheFilled = false;

	const double mean = 0.5;
	const double standardDeviation = 0.5 / Math.PI;

	private double Trunc(double value)
	{
		if (value < 0.0 || value >= 1.0) return this.Sample();
		return value;
	}

	protected override double Sample()
	{
		if (isCacheFilled)
		{
			isCacheFilled = false;
			return cache;
		}

		double r = 0.0;
		double x = 0.0;
		double y = 0.0;

		do
		{
			x = 2.0 * base.Sample() - 1.0;
			y = 2.0 * base.Sample() - 1.0;
			r = x * x + y * y;
		}
		while (r >= 1.0 || r == 0.0);

		double z = Math.Sqrt(-2.0 * Math.Log(r) / r);

		cache = Trunc(mean + standardDeviation * x * z);
		isCacheFilled = true;

		return Trunc(mean + standardDeviation * y * z);
	}
}

serializedForm :: Server was unable to process request

28 March 2008
After the migration of a Microsoft Dynamics CRM 3.0 application to CRM 4.0 and redirecting the BizTalk CRM adapter to the new server we received the following error message from the CRM web service when sending messages:
ErrorCode:   0x80040203
serializedForm :: Server was unable to process request.
After a few hours of puzzling we found out that this exception was caused by the fact that the send message contained an empty element for a CrmDateTime field. For example:
<contact>
  <birthdate></birthdate>
</contact>
When the empty CrmDateTime elements where removed from the message everything runs smoothly again.

Using BizTalk CrossReferencing API for parameters

17 March 2008

BizTalk has a nice feature called cross-referencing which is meant to cross-reference values between two or more systems. Usually this functionality shall be used in mappings through the cross-reference functoids. However CrossReferencing also provides a CrossReferencing Class that can be used directly in orchestration expressions or helper class libraries. This gives you the interesting opportunity to use the cross-referencing database tables to store parameters for your BizTalk applications in one place.

Below is an example of how you can implement a Parameter class that can be used in an orchestration:

using System;
using System.Data.SqlClient;
using Microsoft.BizTalk.CrossReferencing;

namespace Helpers
{
	public static class Parameters
	{
		private const string valXRef = "Helpers.Parameters";
		private const string valAppType = "MyApplication";

		internal static SqlConnection CreateDbConnection()
		{
			SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
			builder.DataSource = CrossReferencing.GetAppValue(valXRef, valAppType, "Server");
			builder.InitialCatalog = CrossReferencing.GetAppValue(valXRef, valAppType, "Database");
			builder.IntegratedSecurity = true;

			SqlConnection connection = new SqlConnection(builder.ConnectionString);
			connection.Open();

			return connection;
		}

		public static bool GoLeft
		{
			get
			{
				string val = CrossReferencing.GetAppValue(valXRef, valAppType, "GoLeft");
				return String.IsNullOrEmpty(val) ? false : Convert.ToBoolean(val);
			}
		}

		public static TimeSpan TimeOut
		{
			get
			{
				string val = CrossReferencing.GetAppValue(valXRef, valAppType, "TimeOut");
				return TimeSpan.FromSeconds(String.IsNullOrEmpty(val) ? 30 : Convert.ToDouble(val));
			}
		}
	}
}

Exception handling with the BizTalk ESB Guidance

12 March 2008

Yesterday I gave a presentation (together with Marcel Fernee of Microsoft) at the Dutch BTUG meeting (http://www.btug.nl) on my experience with the ESB Guidance. Part of the presentation was about the ESB Exception Management Framework and how I use it in the project I am working on.

Quote from the ESB Guidance documentation:

Using the ESB Failed Orchestration Exception Routing mechanism, the process steps are:

  1. Code in the exception handler that detects the error creates a fault message by calling the CreateFaultMessage method. For example:
    // Create fault exception message
    faultMsg = Microsoft.Practices.ESB.ExceptionHandling.ExceptionMgmt.CreateFaultMessage();
  2. The Failed Orchestration Exception Routing mechanism automatically inserts the error description into the fault message context (for example, “The Business Rule Engine threw a divide by zero error processing the LoanProcessing policy”).
  3. The Failed Orchestration Exception Routing mechanism automatically promotes failure- and application-specific properties into the fault message context, setting the values from the current environment. These properties are:
    * Application (auto-populated)
    * DateTime (auto-populated as a UTC value)
    * Description (auto-populated—the exception message)
    * ErrorType (auto-populated—the exception type)
    * MachineName (auto-populated—the current server name)
    * Scope (auto-populated—the Scope shape containing the current exception handler)
    * ServiceName (auto-populated—the orchestration name)
    * ServiceInstanceID (auto-populated—the orchestration instance ID as a GUID)

    WARNINGS:
    The DateTime property is auto-populated with a string in the format of the servers regional date and time settings. If the format can not be mapped by the SQL server adapter, you will get a BizTalk error when the fault message is published to the Exception Management Database. My proposed solution can be found at http://www.codeplex.com/esb/WorkItem/View.aspx?WorkItemId=4430.

    If the auto-populated Description is larger than 256 characters BizTalk itself will give an error when the fault message is published to the message box, because promoted properties cannot be longer. This should be fixed in the source code of the ExceptionMgmt class.

  4. Code in the exception handler sets other properties of the fault message as required, for example:
    // Set fault message properties
    faultMsg.Body.FailureCategory = "MessageBuild";
    faultMsg.Body.FaultCode = 1000;
    faultMsg.Body.FaultDescription = "Some error occurred";
    faultMsg.Body.FaultSeverity = Microsoft.Practices.ESB.ExceptionHandling.FaultSeverity.Severe;
  5. The Failed Orchestration Exception Routing mechanism automatically serializes the current Exception object into the fault message.
  6. Code in the exception handler can optionally add current orchestration messages to the fault message using the AddMessage(faultMsg, messageToAdd) method. This serializes and persists the message, including all of the context properties. For example:
    // Add other current orchestration messages to the fault message
    Microsoft.Practices.ESB.ExceptionHandling.ExceptionMgmt.AddMessage(faultMsg, approvedRequestMsg);
  7. Code in the exception handler publishes the fault message through a direct bound port into the Message Box database.
  8. If publishing succeeds:
    * Orchestration or send port subscriptions can process the fault, rehydrating the Exception object, and extract any added messages complete with their context property values.
    * A global exception handler (a send port) automatically publishes the fault message to the ESB Management Portal.

Below is an example of the catch blocks that we us in our orchestrations. imageIn the Construct exception shape steps 1 to 6 are taken.

Then a Start Orchestration shape is called to start the ExceptionHandler orchestration in the figure below. This is also the place where step 7 is done. Here a very nice, but undocumented, feature of the ESB Guidance Core Framework can be used to log the exception: the EventLogger!

exception = Microsoft.Practices.ESB.ExceptionHandling.ExceptionMgmt.GetException(faultMsg);
Microsoft.Practices.ESB.Exception.Management.EventLogger.LogMessage(
    exception.Message,
    System.Diagnostics.EventLogEntryType.Error,
    (System.Int32)Microsoft.Practices.ESB.Exception.Management.EventLogger.EventId.Default
);

image