We are currently working on improving Mirroring function targeting R3 release. This blog post is though primarily not about that (I will later make a blog post about how the new mirroring architecture is going to be) but about one change that we are about to do. The change is regarding RawProperty.CustomData and how that is handled during import/export (and also mirroring since mirroring uses import/export functionality).
My guess is that not many of you out there has written any code that is affected of this, but if some of you have done that this post might be useful. For you other that have not heard about or used RawProperty.CustomData you might stop read here and do something more useful instead :-)
Previously when a page was exported each "Get" property on the PropertyData (class inheriting PropertyData) instance was called through reflection and the data from that property (given that it was Serializable) was included in the export package as part of the member CustomData on the RawProperty that is in the export package. Due to the performance penalty that comes with usage of reflection we have decided to remove that code. So in R3 there will no longer be any automatically data added to the CustomData field.
However the EPiServer importing code have not used this data previously either so unless you have written any custom event handler on the importing side that relies on that the RawProperty.CustomData contains data your code should not be affected.
It is though still possible to use RawProperty.CustomData field to pass custom data that your PropertyData implementation needs. An example of this is our PropertyXForm that does not contain the XForm itself but a reference to an XForm. In that case we have an event handler on the exporting side that adds the XForm to the RawProperty.CustomData field and then on the importing side we have another event handler that extracts the XForm and creates/updates it on the importing site.
The way to hookup event handlers for the events raised during import/export of properties is shown below
DataExporter.ExportPropertyEvent += new EventHandler<TransformPropertyEventArgs>(PropertyXFormTransform.ExportEventHandler);
DataImporter.ImportPropertyEvent += new EventHandler<TransformPropertyEventArgs>(PropertyXFormTransform.ImportEventHandler);
or to hookup to Mirroring exporter/importer
MirroringDataExporter.ExportPropertyEvent += new EventHandler<TransformPropertyEventArgs>(PropertyXFormTransform.ExportEventHandler);
MirroringDataImporter.ImportPropertyEvent += new EventHandler<TransformPropertyEventArgs>(PropertyXFormTransform.ImportEventHandler);
Below is a pseudo code example of implementation of event handlers that handles import/export of XForm:
public static void ImportEventHandler(object sender, TransformPropertyEventArgs e)
{
...
StringReader formReader = new StringReader(e.PropertySource.CustomData[0].Xml);
XmlSerializer xml = new XmlSerializer(typeof(XForm));
XForm xForm = xml.Deserialize(formReader);
...
xForm.Save();
propDestination.Value = e.PropertySource.Value;
...
e.IsHandled = true;
}
public static void ExportEventHandler(object sender, TransformPropertyEventArgs e)
{
IPageTransferContext transferContext = sender as IPageTransferContext;
if (transferContext == null || e == null || e.IsHandled || e.PropertySource == null || e.PropertySource.TypeName == null || e.PropertySource.TypeName.CompareTo("EPiServer.Core.PropertyXForm") != 0)
{
return;
}
//we need to export the xform definition as well
XForm xForm = XForm.CreateInstance(new Guid(e.PropertySource.Value));
if (xForm != null)
{
StringBuilder writerBuffer = new StringBuilder();
StringWriter txt = new StringWriter(writerBuffer);
XmlSerializer xmlSerializer = new XmlSerializer(typeof(XForm));
xmlSerializer.Serialize(txt, xForm);
RawNameAndXml xFormData = new RawNameAndXml();
xFormData.Name = "Form";
xFormData.Xml = writerBuffer.ToString();
e.PropertySource.CustomData = new RawNameAndXml[1] { xFormData };
}
e.IsHandled = true;
}