Thursday, May 14, 2009

Creating a field in a List and getting the error: "Index was outside the bounds of the array"

Today, while I was code reviewing a new release of our rating field type I got a weird error message...

We added a new feature that adds 2 read only fields with the total number of ratings and number of comments.

Code example for addnig new fields was simple:
if (!list.Fields.ContainsField(ratingField.FieldName_NumOfCommentsInternalName))
{
list.Fields.Add(ratingField.FieldName_NumOfCommentsDecodedName, SPFieldType.Number, false);
//Some more logic here
}


Pretty simple, only when this code runs this time (3rd unit testing sessions before release to customer review) suddenly I get the error message above "Index was outside the bounds of the array".

Well... I ran it in debug few time, scratching my head few times more, but nothing - same error every time!

OK, time for drilling into SharePoint code I guess...
The exception stack trace was as following:
at Microsoft.SharePoint.Utilities.SPStringUtility.EscapedCodeToLower(String str)
at Microsoft.SharePoint.SPFieldCollection.FixFieldV3Attrs(XmlDocument xd, XmlElement xe, Guid& fid, String& name)
at Microsoft.SharePoint.SPFieldCollection.TranslateFieldSchema(String schemaXml, Guid& fid, String& strDisp, String& strStaticNew)
at Microsoft.SharePoint.SPFieldCollection.AddFieldAsXmlInternal(String schemaXml, Boolean addToDefaultView, SPAddFieldOptions op)
at Microsoft.SharePoint.SPFieldCollection.AddFieldAsXml(String schemaXml, Boolean addToDefaultView, SPAddFieldOptions op)
at Microsoft.SharePoint.SPFieldCollection.AddFieldAsXml(String strXml)
at Microsoft.SharePoint.SPFieldCollection.AddInternal(String strDisplayName, SPFieldType type, Boolean bRequired, Boolean bCompactName, Guid lookupListId, Guid lookupWebId, StringCollection choices)
at Microsoft.SharePoint.SPFieldCollection.Add(String strDisplayName, SPFieldType type, Boolean bRequired, Boolean bCompactName, StringCollection choices)
at Microsoft.SharePoint.SPFieldCollection.Add(String strDisplayName, SPFieldType type, Boolean bRequired)
at KWizCom.SharePoint.Rating.ListRatingUtilities.CreateRatingCountFieldsInList(SPWeb web, SPList list, RatingField ratingField)


Revealing that the exception was raised from a method called:
Microsoft.SharePoint.Utilities.SPStringUtility.EscapedCodeToLower(String str)

So far - makes sense... string parsing is always the number one cause for index bound exceptions, right?

So, I wanted to check what was wrong with the field name I was trying to create...
ratingField.FieldName_NumOfCommentsDecodedName "2Rating Site Column_x" string


See that my field name ends with "_x"...

The code I extracted from "EscapedCodeToLower" had the following line in it:
if (((str[i] == '_') && (i < (str.Length - 1))) && (str[i + 1] == 'x'))


Well, now everything was clear to me.

Microsoft uses "XmlConvert.EncodeName" in order to encode fields internal names in SharePoint. This encoding method replaces illegal characters with "_x0020_" for example. Apparently this method looks up every "_" that was followed by "x" and assumes it is a token it needs to decode... But what happens if my text ends with "_x"?

Aha! You get your "Index was outside the bounds of the array" exception!

So, I guess now I have to add a check to my code. I Doubt anyone would notice it or bother to fix it.

Well, I googled that error message regarding SPList.Fields.Add and got nothing - hopefully this will help someone in need in the future...

Shai.

No comments: