Second Life of a Hungarian SharePoint Geek

October 17, 2010

Decoding the content of the BinarySerializedWebPart – The code

Note: this is the second part of a former post. If you happen to have questions, please check the first part (that is about the theory) before asking something you may find the answer for in the first part.

Well, after so much theory I feel it is time to write some code for decoding of BinarySerializedWebPart.

Let’s see my former sample XML:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  3.   <Module Name="FileSystemForms" Url="Lists/Files" RootWebOnly="FALSE" SetupPath="pages">
  4.     <File Url="DispForm.aspx" Type="Ghostable" Path="form.aspx">
  5.       <BinarySerializedWebPart>
  6.         <GUIDMap>
  7.           <GUID Id="33ff2881_489d_4ce2_ac94_e81d64689d2a" ListUrl="Lists/Files" />
  8.         </GUIDMap>
  9.         <WebPart ID="{035cec7d-5f69-4dbf-a551-0b8203467c41}" WebPartIdProperty="" List="{$ListId:Lists/Files;}" Type="4"
  10.           Flags="0" DisplayName="" Version="4" Url="Lists/Files/DispForm.aspx" WebPartOrder="1" WebPartZoneID="Main"
  11.           IsIncluded="True" FrameState="0" WPTypeId="{feaafd58-2dc9-e199-be37-d6cdd7f84690}"
  12.           SolutionId="{00000000-0000-0000-0000-000000000000}" Assembly="" Class="" Src=""
  13.           AllUsers="B6Dt/kMAAAABAAAAAAAAAAIAAAAvX2xheW91dHMvaW1hZ2VzL2l0ZWJsLnBuZwAvRjFTaXRlL0xpc3RzL0ZpbGVzAP8BFCsAJQICAgMCAwEEAAICAhICFAEBAAIEBQtDb250cm9sTW9kZQspiAFNaWNyb3NvZnQuU2hhcmVQb2ludC5XZWJDb250cm9scy5TUENvbnRyb2xNb2RlLCBNaWNyb3NvZnQuU2hhcmVQb2ludCwgVmVyc2lvbj0xNC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj03MWU5YmNlMTExZTk0MjljAQUIRm9ybVR5cGUCBAEAAAIWAoYBCyo0U3lzdGVtLldlYi5VSS5XZWJDb250cm9scy5XZWJQYXJ0cy5XZWJQYXJ0RXhwb3J0TW9kZQICggEFGi9fbGF5b3V0cy9pbWFnZXMvaXRlYmwucG5nAn0FEy9GMVNpdGUvTGlzdHMvRmlsZXMFCFBhZ2VUeXBlCyl3TWljcm9zb2Z0LlNoYXJlUG9pbnQuUEFHRVRZUEUsIE1pY3Jvc29mdC5TaGFyZVBvaW50LCBWZXJzaW9uPTE0LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTcxZTliY2UxMTFlOTQyOWMEBQdMaXN0VXJsZQUGTGlzdElkKClYU3lzdGVtLkd1aWQsIG1zY29ybGliLCBWZXJzaW9uPTIuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OSQzM2ZmMjg4MS00ODlkLTRjZTItYWM5NC1lODFkNjQ2ODlkMmEFD0xpc3REaXNwbGF5TmFtZWUClQEFJnszM0ZGMjg4MS00ODlELTRDRTItQUM5NC1FODFENjQ2ODlEMkF9BQ1YbWxEZWZpbml0aW9uBcUPDQo8VXNlckNvbnRyb2wgeDpDbGFzcz0iRm9ybVhtbFRvWGFtbC5Vc2VyQ29udHJvbDIiIHhtbG5zOng9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd2luZngvMjAwNi94YW1sIiB4bWxuczpTaGFyZVBvaW50PSJNaWNyb3NvZnQuU2hhcmVQb2ludC5XZWJDb250cm9scyIgeG1sbnM6c3lzdGVtPSJjbHItbmFtZXNwYWNlOlN5c3RlbTthc3NlbWJseT1tc2NvcmxpYiI+PFN0YWNrUGFuZWwgeDpOYW1lPSJGb3JtIj4NCjxTdGFja1BhbmVsLlJlc291cmNlcz4NCjxzeXN0ZW06U3RyaW5nIHg6S2V5PSJGb3JtTW9kZSI+RGlzcGxheTwvc3lzdGVtOlN0cmluZz4NCjxzeXN0ZW06U3RyaW5nIHg6S2V5PSJGb3JtVHlwZSI+TGlzdEZvcm08L3N5c3RlbTpTdHJpbmc+DQo8L1N0YWNrUGFuZWwuUmVzb3VyY2VzPg0KPFN0YWNrUGFuZWwgeDpOYW1lPSJNYWluU2VjdGlvbnMiPjxHcmlkPjxHcmlkLkNvbHVtbkRlZmluaXRpb25zPg0KPENvbHVtbkRlZmluaXRpb24gU3R5bGU9IntTdGF0aWNSZXNvdXJjZSBtcy1mb3JtbGFiZWx9Ii8+DQo8Q29sdW1uRGVmaW5pdGlvbiBTdHlsZT0ie1N0YXRpY1Jlc291cmNlIG1zLWZvcm1ib2R5fSIvPg0KPC9HcmlkLkNvbHVtbkRlZmluaXRpb25zPjxHcmlkLlJvd0RlZmluaXRpb25zPg0KPFJvd0RlZmluaXRpb24gLz4NCjxSb3dEZWZpbml0aW9uIC8+DQo8Um93RGVmaW5pdGlvbiAvPg0KPFJvd0RlZmluaXRpb24gLz4NCjwvR3JpZC5Sb3dEZWZpbml0aW9ucz4NCjxTaGFyZVBvaW50OkZpZWxkTGFiZWwgR3JpZC5Db2x1bW49IjAiIEdyaWQuUm93PSIwIiBDb250cm9sTW9kZT0iRGlzcGxheSIgRmllbGROYW1lPSJOYW1lIiAvPg0KPENvbW1lbnQgRmllbGROYW1lPSJOYW1lIiBGaWVsZEludGVybmFsTmFtZT0iTmFtZSIgRmllbGRUeXBlPSJUZXh0IiAvPg0KPFNoYXJlUG9pbnQ6Rm9ybUZpZWxkIEdyaWQuQ29sdW1uPSIxIiBHcmlkLlJvdz0iMCIgQ29udHJvbE1vZGU9IkRpc3BsYXkiIEZpZWxkTmFtZT0iTmFtZSIgSW5jbHVkZURlc2NyaXB0aW9uPSJUcnVlIi8+DQo8U2hhcmVQb2ludDpGaWVsZExhYmVsIEdyaWQuQ29sdW1uPSIwIiBHcmlkLlJvdz0iMSIgQ29udHJvbE1vZGU9IkRpc3BsYXkiIEZpZWxkTmFtZT0iU2l6ZSIgLz4NCjxDb21tZW50IEZpZWxkTmFtZT0iU2l6ZSIgRmllbGRJbnRlcm5hbE5hbWU9IlNpemUiIEZpZWxkVHlwZT0iSW50ZWdlciIgLz4NCjxTaGFyZVBvaW50OkZvcm1GaWVsZCBHcmlkLkNvbHVtbj0iMSIgR3JpZC5Sb3c9IjEiIENvbnRyb2xNb2RlPSJEaXNwbGF5IiBGaWVsZE5hbWU9IlNpemUiIEluY2x1ZGVEZXNjcmlwdGlvbj0iVHJ1ZSIvPg0KPFNoYXJlUG9pbnQ6RmllbGRMYWJlbCBHcmlkLkNvbHVtbj0iMCIgR3JpZC5Sb3c9IjIiIENvbnRyb2xNb2RlPSJEaXNwbGF5IiBGaWVsZE5hbWU9IkNyZWF0ZWQiIC8+DQo8Q29tbWVudCBGaWVsZE5hbWU9IkNyZWF0ZWQiIEZpZWxkSW50ZXJuYWxOYW1lPSJDcmVhdGVkIiBGaWVsZFR5cGU9IkRhdGVUaW1lIiAvPg0KPFNoYXJlUG9pbnQ6Rm9ybUZpZWxkIEdyaWQuQ29sdW1uPSIxIiBHcmlkLlJvdz0iMiIgQ29udHJvbE1vZGU9IkRpc3BsYXkiIEZpZWxkTmFtZT0iQ3JlYXRlZCIgSW5jbHVkZURlc2NyaXB0aW9uPSJUcnVlIi8+DQo8U2hhcmVQb2ludDpGaWVsZExhYmVsIEdyaWQuQ29sdW1uPSIwIiBHcmlkLlJvdz0iMyIgQ29udHJvbE1vZGU9IkRpc3BsYXkiIEZpZWxkTmFtZT0iTGFzdE1vZGlmaWVkIiAvPg0KPENvbW1lbnQgRmllbGROYW1lPSJMYXN0IG1vZGlmaWVkIiBGaWVsZEludGVybmFsTmFtZT0iTGFzdE1vZGlmaWVkIiBGaWVsZFR5cGU9IkRhdGVUaW1lIiAvPg0KPFNoYXJlUG9pbnQ6Rm9ybUZpZWxkIEdyaWQuQ29sdW1uPSIxIiBHcmlkLlJvdz0iMyIgQ29udHJvbE1vZGU9IkRpc3BsYXkiIEZpZWxkTmFtZT0iTGFzdE1vZGlmaWVkIiBJbmNsdWRlRGVzY3JpcHRpb249IlRydWUiLz4NCjwvR3JpZD4NCjwvU3RhY2tQYW5lbD4NCjwvU3RhY2tQYW5lbD4NCjwvVXNlckNvbnRyb2w+AktkBRFQYXJhbWV0ZXJCaW5kaW5ncwXoAg0KPFBhcmFtZXRlckJpbmRpbmcgTmFtZT0iZHZ0X2Fwb3MiIExvY2F0aW9uPSJQb3N0YmFjaztDb25uZWN0aW9uIi8+DQogICAgICAgIDxQYXJhbWV0ZXJCaW5kaW5nIE5hbWU9IlVzZXJJRCIgTG9jYXRpb249IkNBTUxWYXJpYWJsZSIgRGVmYXVsdFZhbHVlPSJDdXJyZW50VXNlck5hbWUiLz4NCiAgICAgICAgPFBhcmFtZXRlckJpbmRpbmcgTmFtZT0iVG9kYXkiIExvY2F0aW9uPSJDQU1MVmFyaWFibGUiIERlZmF1bHRWYWx1ZT0iQ3VycmVudERhdGUiLz4NCiAgICAgICAgPFBhcmFtZXRlckJpbmRpbmcgTmFtZT0iTGlzdEl0ZW1JZCIgTG9jYXRpb249IlF1ZXJ5U3RyaW5nKElEKSIgRGVmYXVsdFZhbHVlPSIwIi8+DQogICAgICAgIA==" />
  14.       </BinarySerializedWebPart>
  15.       </File>
  16.     </Module>
  17. </Elements>

The DeserializeWebPart method below shows the decoding process of the encoded web part. It first read and Base64 decode the binary serialized attribute value, then instantiate the BinaryWebPartDeserializer via calling its protected constructor, and gets the web part by calling the internal Deserialize method. Note, that we get the SPWebPartManager we need also using Reflection, by reading the internal WebPartManager property of the SPWeb instance passed to the method as parameter. I assume you can use any SPWeb instance here, but it requires yet further testing.

In the XML in this example, there is only an AllUsers attribute. If your XML contains PerUser and/or View attributes, you should read those values too, and include them as parameters when calling the constructor of the BinaryWebPartDeserializer.

In this example I knew that the result must be an XsltListViewWebPart, so I used that fixed type in the code. If you are not sure in the web part type, I will show you a method in a following post how to get the type from the XML either.

  1. public WebPart DeserializeWebPart(SPWeb web, String xmlPath)
  2. {
  3.     
  4.     XmlDocument sampleXml = new XmlDocument();
  5.     sampleXml.Load(xmlPath);
  6.     XmlNamespaceManager nsmgr = new XmlNamespaceManager(sampleXml.NameTable);
  7.     nsmgr.AddNamespace("sp", "http://schemas.microsoft.com/sharepoint/&quot;);
  8.     XmlNode webPartNode = sampleXml.SelectSingleNode("sp:Elements/sp:Module/sp:File/sp:BinarySerializedWebPart/sp:WebPart", nsmgr);
  9.  
  10.     byte[] allUsers = GetBinarySerializedAttribute("AllUsers", webPartNode);
  11.     //byte[] perUser = GetBinarySerializedAttribute("PerUser", webPartNode);
  12.     //byte[] view = GetBinarySerializedAttribute("View", webPartNode);
  13.     
  14.     Assembly assembly = typeof(SPSite).Assembly;
  15.     
  16.     Type spWebPartManagerType = typeof(SPWebPartManager);
  17.     Type xmlNamespaceManagerType = typeof(XmlNamespaceManager);
  18.     Type spWebType = typeof(SPWeb);
  19.     Type typeType = typeof(Type);
  20.     Type stringArrayType = typeof(String).MakeArrayType();
  21.     Type byteArrayType = typeof(byte).MakeArrayType();
  22.     // or alternatively we could use
  23.     //Type byteArrayType = typeof(byte[]);
  24.     Type stringType = typeof(String);
  25.     Type xsltListViewWebPartType = typeof(XsltListViewWebPart);
  26.  
  27.     PropertyInfo pi_WebPartManager = spWebType.GetProperty("WebPartManager", BindingFlags.NonPublic | BindingFlags.Instance);
  28.     SPWebPartManager spWebPartManager = (SPWebPartManager)pi_WebPartManager.GetValue(web, null);
  29.  
  30.     Type binaryWebPartDeserializerType = assembly.GetType("Microsoft.SharePoint.WebPartPages.BinaryWebPartDeserializer");
  31.     // protected BinaryWebPartDeserializer(SPWebPartManager webPartManager, XmlNamespaceManager xmlnsManager, byte[] userData, byte[] sharedData, string webPartIdProperty, string[] links, Type type, SPWeb spWeb) : base(webPartManager)
  32.     ConstructorInfo ci_BinaryWebPartDeserializerType = binaryWebPartDeserializerType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance,
  33.          null, new Type[8] { spWebPartManagerType, xmlNamespaceManagerType, byteArrayType, byteArrayType, stringType, stringArrayType, typeType, spWebType }, null);
  34.     object binaryWebPartDeserializer = ci_BinaryWebPartDeserializerType.Invoke(new object[8] { null, null, null, allUsers, null, null, xsltListViewWebPartType, null });
  35.     MethodInfo mi_Deserialize = binaryWebPartDeserializerType.GetMethod("Deserialize", BindingFlags.NonPublic | BindingFlags.Instance);
  36.     WebPart webPart = (WebPart)mi_Deserialize.Invoke(binaryWebPartDeserializer, null);
  37.  
  38.     return webPart;
  39. }

Note, that the BinarySerializedWebPart node might be found in other context either. See the following example:

  1. <View List="Shared Documents" DisplayName="" Url="" DefaultView="FALSE" BaseViewID="1" Type="HTML" WebPartOrder="0" WebPartZoneID="Left" ContentTypeID="0x" ID="g_ba709f71_6af5_4e3c_a8b1_01be2d3f95e8" Hidden="TRUE">
  2.   <BinarySerializedWebPart>
  3.     <GUIDMap>
  4.       <GUID Id="33ff2881_489d_4ce2_ac94_e81d64689d2a" ListUrl="Lists/Files" />
  5.     </GUIDMap>
  6.     <WebPart ID="{035cec7d-5f69-4dbf-a551-0b8203467c41}" WebPartIdProperty="" List="{$ListId:Lists/Files;}" Type="4"
  7.              Flags="0" DisplayName="" Version="4" Url="Lists/Files/DispForm.aspx" WebPartOrder="1" WebPartZoneID="Main"
  8.              IsIncluded="True" FrameState="0" WPTypeId="{feaafd58-2dc9-e199-be37-d6cdd7f84690}"
  9.              SolutionId="{00000000-0000-0000-0000-000000000000}" Assembly="" Class="" Src=""
  10.              AllUsers="B6Dt/kMAAAABAAAAAAAAAAIAAAAvX2xheW91dHMvaW1hZ2VzL2l0ZWJsLnBuZwAvRjFTaXRlL0xpc3RzL0ZpbGVzAP8BFCsAJQICAgMCAwEEAAICAhICFAEBAAIEBQtDb250cm9sTW9kZQspiAFNaWNyb3NvZnQuU2hhcmVQb2ludC5XZWJDb250cm9scy5TUENvbnRyb2xNb2RlLCBNaWNyb3NvZnQuU2hhcmVQb2ludCwgVmVyc2lvbj0xNC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj03MWU5YmNlMTExZTk0MjljAQUIRm9ybVR5cGUCBAEAAAIWAoYBCyo0U3lzdGVtLldlYi5VSS5XZWJDb250cm9scy5XZWJQYXJ0cy5XZWJQYXJ0RXhwb3J0TW9kZQICggEFGi9fbGF5b3V0cy9pbWFnZXMvaXRlYmwucG5nAn0FEy9GMVNpdGUvTGlzdHMvRmlsZXMFCFBhZ2VUeXBlCyl3TWljcm9zb2Z0LlNoYXJlUG9pbnQuUEFHRVRZUEUsIE1pY3Jvc29mdC5TaGFyZVBvaW50LCBWZXJzaW9uPTE0LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTcxZTliY2UxMTFlOTQyOWMEBQdMaXN0VXJsZQUGTGlzdElkKClYU3lzdGVtLkd1aWQsIG1zY29ybGliLCBWZXJzaW9uPTIuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OSQzM2ZmMjg4MS00ODlkLTRjZTItYWM5NC1lODFkNjQ2ODlkMmEFD0xpc3REaXNwbGF5TmFtZWUClQEFJnszM0ZGMjg4MS00ODlELTRDRTItQUM5NC1FODFENjQ2ODlEMkF9BQ1YbWxEZWZpbml0aW9uBcUPDQo8VXNlckNvbnRyb2wgeDpDbGFzcz0iRm9ybVhtbFRvWGFtbC5Vc2VyQ29udHJvbDIiIHhtbG5zOng9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd2luZngvMjAwNi94YW1sIiB4bWxuczpTaGFyZVBvaW50PSJNaWNyb3NvZnQuU2hhcmVQb2ludC5XZWJDb250cm9scyIgeG1sbnM6c3lzdGVtPSJjbHItbmFtZXNwYWNlOlN5c3RlbTthc3NlbWJseT1tc2NvcmxpYiI+PFN0YWNrUGFuZWwgeDpOYW1lPSJGb3JtIj4NCjxTdGFja1BhbmVsLlJlc291cmNlcz4NCjxzeXN0ZW06U3RyaW5nIHg6S2V5PSJGb3JtTW9kZSI+RGlzcGxheTwvc3lzdGVtOlN0cmluZz4NCjxzeXN0ZW06U3RyaW5nIHg6S2V5PSJGb3JtVHlwZSI+TGlzdEZvcm08L3N5c3RlbTpTdHJpbmc+DQo8L1N0YWNrUGFuZWwuUmVzb3VyY2VzPg0KPFN0YWNrUGFuZWwgeDpOYW1lPSJNYWluU2VjdGlvbnMiPjxHcmlkPjxHcmlkLkNvbHVtbkRlZmluaXRpb25zPg0KPENvbHVtbkRlZmluaXRpb24gU3R5bGU9IntTdGF0aWNSZXNvdXJjZSBtcy1mb3JtbGFiZWx9Ii8+DQo8Q29sdW1uRGVmaW5pdGlvbiBTdHlsZT0ie1N0YXRpY1Jlc291cmNlIG1zLWZvcm1ib2R5fSIvPg0KPC9HcmlkLkNvbHVtbkRlZmluaXRpb25zPjxHcmlkLlJvd0RlZmluaXRpb25zPg0KPFJvd0RlZmluaXRpb24gLz4NCjxSb3dEZWZpbml0aW9uIC8+DQo8Um93RGVmaW5pdGlvbiAvPg0KPFJvd0RlZmluaXRpb24gLz4NCjwvR3JpZC5Sb3dEZWZpbml0aW9ucz4NCjxTaGFyZVBvaW50OkZpZWxkTGFiZWwgR3JpZC5Db2x1bW49IjAiIEdyaWQuUm93PSIwIiBDb250cm9sTW9kZT0iRGlzcGxheSIgRmllbGROYW1lPSJOYW1lIiAvPg0KPENvbW1lbnQgRmllbGROYW1lPSJOYW1lIiBGaWVsZEludGVybmFsTmFtZT0iTmFtZSIgRmllbGRUeXBlPSJUZXh0IiAvPg0KPFNoYXJlUG9pbnQ6Rm9ybUZpZWxkIEdyaWQuQ29sdW1uPSIxIiBHcmlkLlJvdz0iMCIgQ29udHJvbE1vZGU9IkRpc3BsYXkiIEZpZWxkTmFtZT0iTmFtZSIgSW5jbHVkZURlc2NyaXB0aW9uPSJUcnVlIi8+DQo8U2hhcmVQb2ludDpGaWVsZExhYmVsIEdyaWQuQ29sdW1uPSIwIiBHcmlkLlJvdz0iMSIgQ29udHJvbE1vZGU9IkRpc3BsYXkiIEZpZWxkTmFtZT0iU2l6ZSIgLz4NCjxDb21tZW50IEZpZWxkTmFtZT0iU2l6ZSIgRmllbGRJbnRlcm5hbE5hbWU9IlNpemUiIEZpZWxkVHlwZT0iSW50ZWdlciIgLz4NCjxTaGFyZVBvaW50OkZvcm1GaWVsZCBHcmlkLkNvbHVtbj0iMSIgR3JpZC5Sb3c9IjEiIENvbnRyb2xNb2RlPSJEaXNwbGF5IiBGaWVsZE5hbWU9IlNpemUiIEluY2x1ZGVEZXNjcmlwdGlvbj0iVHJ1ZSIvPg0KPFNoYXJlUG9pbnQ6RmllbGRMYWJlbCBHcmlkLkNvbHVtbj0iMCIgR3JpZC5Sb3c9IjIiIENvbnRyb2xNb2RlPSJEaXNwbGF5IiBGaWVsZE5hbWU9IkNyZWF0ZWQiIC8+DQo8Q29tbWVudCBGaWVsZE5hbWU9IkNyZWF0ZWQiIEZpZWxkSW50ZXJuYWxOYW1lPSJDcmVhdGVkIiBGaWVsZFR5cGU9IkRhdGVUaW1lIiAvPg0KPFNoYXJlUG9pbnQ6Rm9ybUZpZWxkIEdyaWQuQ29sdW1uPSIxIiBHcmlkLlJvdz0iMiIgQ29udHJvbE1vZGU9IkRpc3BsYXkiIEZpZWxkTmFtZT0iQ3JlYXRlZCIgSW5jbHVkZURlc2NyaXB0aW9uPSJUcnVlIi8+DQo8U2hhcmVQb2ludDpGaWVsZExhYmVsIEdyaWQuQ29sdW1uPSIwIiBHcmlkLlJvdz0iMyIgQ29udHJvbE1vZGU9IkRpc3BsYXkiIEZpZWxkTmFtZT0iTGFzdE1vZGlmaWVkIiAvPg0KPENvbW1lbnQgRmllbGROYW1lPSJMYXN0IG1vZGlmaWVkIiBGaWVsZEludGVybmFsTmFtZT0iTGFzdE1vZGlmaWVkIiBGaWVsZFR5cGU9IkRhdGVUaW1lIiAvPg0KPFNoYXJlUG9pbnQ6Rm9ybUZpZWxkIEdyaWQuQ29sdW1uPSIxIiBHcmlkLlJvdz0iMyIgQ29udHJvbE1vZGU9IkRpc3BsYXkiIEZpZWxkTmFtZT0iTGFzdE1vZGlmaWVkIiBJbmNsdWRlRGVzY3JpcHRpb249IlRydWUiLz4NCjwvR3JpZD4NCjwvU3RhY2tQYW5lbD4NCjwvU3RhY2tQYW5lbD4NCjwvVXNlckNvbnRyb2w+AktkBRFQYXJhbWV0ZXJCaW5kaW5ncwXoAg0KPFBhcmFtZXRlckJpbmRpbmcgTmFtZT0iZHZ0X2Fwb3MiIExvY2F0aW9uPSJQb3N0YmFjaztDb25uZWN0aW9uIi8+DQogICAgICAgIDxQYXJhbWV0ZXJCaW5kaW5nIE5hbWU9IlVzZXJJRCIgTG9jYXRpb249IkNBTUxWYXJpYWJsZSIgRGVmYXVsdFZhbHVlPSJDdXJyZW50VXNlck5hbWUiLz4NCiAgICAgICAgPFBhcmFtZXRlckJpbmRpbmcgTmFtZT0iVG9kYXkiIExvY2F0aW9uPSJDQU1MVmFyaWFibGUiIERlZmF1bHRWYWx1ZT0iQ3VycmVudERhdGUiLz4NCiAgICAgICAgPFBhcmFtZXRlckJpbmRpbmcgTmFtZT0iTGlzdEl0ZW1JZCIgTG9jYXRpb249IlF1ZXJ5U3RyaW5nKElEKSIgRGVmYXVsdFZhbHVlPSIwIi8+DQogICAgICAgIA==" />
  11.   </BinarySerializedWebPart>
  12. </View>

For this type of XML, you can get the node using the code:

  1. XmlDocument sampleXml = new XmlDocument();
  2. sampleXml.Load(xmlPath);
  3. XmlNode webPartNode = sampleXml.SelectSingleNode("View/BinarySerializedWebPart/WebPart");

No let’s see the helper methods I used. First there is the GetBinarySerializedAttribute method that reads and Base64 decodes the attribute value. It returns only the byte array that we can be used later in the Deserialize method of the ObjectStateFormatter class. So we have to look for the leading xFF x01 byte pattern in the decoded byte array. In this case I chose not the most sophisticated way of search: I simple convert the byte array to a hexadecimal representation and look for the position of the “-FF-01” substring. Since we have not to work with large streams and byte pattern, this algorithm is good / quick enough and provides hopefully more readable code than an arbitrary byte pattern finder implementation.

  1. private byte[] GetBinarySerializedAttribute(String attributeName, XmlNode webPartNode)
  2. {
  3.     byte[] decodedBytes = null;
  4.     XmlAttribute attribute = webPartNode.Attributes[attributeName];
  5.     if (attribute != null)
  6.     {
  7.         String serializedValue = attribute.Value;
  8.         decodedBytes = Convert.FromBase64String(serializedValue);
  9.     }
  10.  
  11.     String fullHexString = ByteArrayToString(decodedBytes);
  12.     int startPos = fullHexString.IndexOf("-FF-01");
  13.     String contentHexString = fullHexString.Substring(startPos);
  14.     byte[] result = StringToByteArray(contentHexString);
  15.  
  16.  
  17.     // this few lines of code only to test the result of deserialization
  18.     // you can remove it
  19.     ObjectStateFormatter formatter = new ObjectStateFormatter();
  20.     if ((result != null) && (result.Length != 0))
  21.     {
  22.         Object deserialized = formatter.Deserialize(new MemoryStream(result));
  23.     }
  24.     // end of testing block
  25.  
  26.     return result;
  27. }

Part of this method is only to test what type of object the deserialization will result. In my experience it is a simple object array as shown here:

image

Further helper methods for byte array – string conversions:

  1. public byte[] StringToByteArray(String hex)
  2. {
  3.     int NumberChars = hex.Length;
  4.     byte[] bytes = new byte[NumberChars / 3];
  5.     for (int i = 0; i < NumberChars; i += 3)
  6.         bytes[i / 3] = Convert.ToByte(hex.Substring(i + 1, 2), 16);
  7.     return bytes;
  8. }
  9.  
  10. private string ByteArrayToString(byte[] ba)
  11. {
  12.     string hex = BitConverter.ToString(ba);
  13.     // append a leading – to the hex string to ensure each byte is 3 chars
  14.     return "-" + hex;
  15. }

Hopefully the code runs successfully and return the deserialized WebPart. From this object you can get the values you need either writing out the necessary properties or simply via checking the properties in Visual Studio IDE.

image

Advertisements

6 Comments »

  1. […] step forward « Validation issues with external lists (or have I missed something?) Decoding the content of the BinarySerializedWebPart – The code […]

    Pingback by Decoding the content of the BinarySerializedWebPart – The theory « Second Life of a Hungarian SharePoint Geek — October 17, 2010 @ 23:13

  2. […] Second Life of a Hungarian SharePoint Geek If your sword is too short, take one step forward « Decoding the content of the BinarySerializedWebPart – The code […]

    Pingback by Getting the type of the web part from a BinarySerializedWebPart « Second Life of a Hungarian SharePoint Geek — October 17, 2010 @ 23:31

  3. Do you happen to have a solution available?

    Thanks,
    Dan

    Comment by Dan Tshin — November 19, 2010 @ 10:14

    • Hi Dan,

      I’ve not published a solution (if you mean Visual Studio 2010 solution) for this post, but hopefully you can find all the required methods in the code snippets above. Sorry for the inconvenience!

      Peter

      Comment by Peter Holpar — December 2, 2010 @ 22:31

  4. I tried this code and was not able to make it work. I always receive “Invalid data serialisation” error. Not sure if it’s my implementation or just the approach that dont work at all.

    Note : I’m trying to deserialize a webpart that was saved from another server.

    Comment by Lord Voldemort — June 23, 2012 @ 19:21

  5. Hi I’ve a big problem. My BinarySerializedWebPart, WebPart xmlnode in View attribute there is a NON base64 Encode String

    Thank’s

    Comment by Paolo Cristina — January 29, 2014 @ 18:41


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: