Wednesday, December 3, 2008

BDC Refresh causes null pointer exception

The current status:

Executing a BDC refresh in specific cirsumstances causes a null pointer exception to be thrown by SharePoint.


Scenario #1:
  1. Add a BDC column without related columns to a list
  2. Add row(s) to the list and assign values to the BDC field
  3. Update the BDC column to use additional related fields
  4. Refresh the BDC column in the list
Result:
After clicking the refresh button and 'OK' on the next page, the next page displays a progress bar, then displays the following error: "An error occurred while retrieving data from . Administrators, see the server log for more information."

The log contains the following line:
Exception thrown while synchronizing business data System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.SharePoint.Portal.WebControls.BusinessDataSynchronizerJob.UpdateListItem(SPListItem item, BusinessDataField bizDataField, LobSystemInstance sysinst, Entity entity, View view, String[] secondaryBdcFieldNames, String[] secondaryWssFieldNames)
at Microsoft.SharePoint.Portal.WebControls.BusinessDataSynchronizerJob.DoWork()



Scenario #2
  1. Add a BDC column with related fields to a list
  2. Add row(s) to the list where the related fields have non-empty values
  3. Refresh the BDC column in the list
Result: Works fine


Scenario #3:
  1. Add a BDC column with related fields to a list
  2. Add row(s) to the list where the related fields have empty or null values
  3. Refresh the BDC column in the list
Result: Throws null pointer exception as described above.


I'll contend that this is a bug for the following reason: reflecting on the Microsoft.SharePoint.Portal.WebControls.BusinessDataSynchronizerJob class that is throwing the exception yields a segment of code that checks the current value of the related field to the updated value retrieved from the BDC LineOfBusiness. If the two values are different, then it sets the item's value for that related field to the updated BDC value.

.NET Reflector gives the following code snippets that are useful:

Label_0144:
str = item[secondaryWssFieldNames[num2]].ToString();
str2 = Convert.ToString(instance.GetFormatted(field), CultureInfo.InvariantCulture);
if (!(str != str2))
{
goto Label_00F6;
}
goto Label_0113;
Label_0113:
flag = true;
item[secondaryWssFieldNames[num2]] = str2;
goto Label_00F6;

Label_001D:
if (flag)
{
item.Update();
}

Label_0144 creates str and str2 to compare the original (str) value and the updated (str2) value. If they are different, then Label_0113 sets the item's value to the updated value and sets Flag to true. Label001D checks the flag value and, if true, updates the item. This should only update items that have actually been updated.

(by the way, this is all SP1 code, post-Infrastructure update)

It seems a viable candidate for this null pointer exception would be the line str = item[secondaryWssFieldNames[num2]].ToString();. If the item's value is null, then the ToString() would obviously fail.

A quick PowerShell script shows that following scenario #1 above yields a null value for the related column. This is indeed a valid candidate for this issue.

If this is the case, has this been brought to Microsoft's attention? Is this addressed in any hotfix or update for SharePoint?

Disable BDC Refresh icon

To disable (properly, to not render) the BDC Refresh "hurricane" icon (as some have called it), simply edit the fldtypes_spsbizdata.xml file and find the <!-- Update link --> XML comment. Below this XML comment, remove/comment the following lines:

<HTML>&nbsp;<![CDATA[<a style="padding-left:2px;padding-right:12px" href="]]></HTML>
<HttpVDir/>
<HTML><![CDATA[/_layouts/BusinessDataSynchronizer.aspx?ListId=]]></HTML>
<ListProperty Select='Name'/>
<HTML><![CDATA[&ColumnName=]]></HTML>
<Property Select='Name'/>
<HTML><![CDATA[" OnClick="GoToLink(this);return false;">]]></HTML>
<HTML><![CDATA[<img border="0" src="/_layouts/images/bdupdate.gif" alt="$Resources:spscore,BusinessDataField_UpdateImageAlt;"/></a>]]></HTML>

Save the file, then perform an IIS reset. After reset, the BDC Refresh icon will be gone. Note that this changes all BDC columns in the site.

While you're editing this file, go ahead and fix the BDC CSS styling bug.

Wednesday, November 12, 2008

Bug in fldtypes_spsbizdata.xml

The css styling for displaying tables inline for BDC columns is not correct into the fldtypes_spsbizdata.xml file. To correct, simply replace "display=inline" with "display:inline;" and reset IIS.

In some environments, this does not cause a problem. However in some situations (perhaps with custom css and master page styling), if the BDC column is used to group a view, the column header does not render properly.

Wednesday, August 8, 2007

Group By Date Field off by one day

I've recently noticed that, when creating a list view that groups by a date field, the date field can be off by one day.

The issue comes when grouping by a date field and setting the default behavior to Collapsed.

It doesn't matter that the Expires date is just a date and not a Date/Time: the same bug appears with fields using both properties (with any time of the day).

The bug does not appear when converting a view to an XSLT view, although you lose much of the customizations and nifty interaction you get with a SharePoint DataView.

If I can get Windows Live Writer configured to upload images, I'll attach screenshots.

Monday, August 6, 2007

Differences in handling CR/LF differences between InfoPath and SharePoint

Although InfoPath claims to handle CR, LF, and CR/LF the same, it does not follow the conventions of other Microsoft products when it comes to generating new line characters.  SharePoint, like most (if not all) Windows applications, uses the CR/LF combination (0x0D, 0x0A) to denote a new line.  This is apparent when viewing the raw data contained within a Multiline Text field.

If you are creating an InfoPath form that submits to a SharePoint library, you can set specific fields within the InfoPath form to be promoted to the SharePoint list.  You can also promote a field within a repeating group.  When you promote this field, you have the option of promoting the first or last item in the list, the number of items in the group, or the entire collection of that field merged into one field. 

When choose the fourth option, a Multiline text field is generated by InfoPath in the SharePoint library.  However, when submitting, the merged fields are separated by only a Line Feed character (0x0A)!

This issue will come into play when you want to perform operations on the SharePoint list through the SharePoint object model.  Dot-matching, for instance, may not work because the .NET Regex processor will use CR/LF as its newline character(s) and won't match the single LF character.  SharePoint Designer may also have difficulty if you want to use substring to parse items from the merged list.

The only fix known so far is to simply remember that merged fields that InfoPath uses will have only the LF character, while other SharePoint-created multiline text fields will use CR/LF.

Thursday, July 26, 2007

Blogging with SharePoint 2007 and Windows Live Writer

I'm sure there are a handful of posting out there about blogging on SharePoint 2007 with Windows Live Writer, which is what I'm using now to publish to BlogSpot.  Microsoft's made it very easy to publish blog posts to SharePoint, including automatic image storage.  I haven't seen any blog posting about it yet, so I'll offer a simple one of my own.

Since the blog's Posts is a list, the images are stored as attachments to that list item.  They would be stored in the /Lists/Posts/Attachments/<Post Id> directory structure for easy reference.  The file names are generated as image.png, image_1.png, etc.

You can also publish with Word 2007 (yet to see if Word 2003 can do the trick), but the images are saved into the Photos.  The file names are generated with the date and the name of the posting (072607_1337_Testing1.png, 072607_1337_Testing2.png, etc).  Not sure if 1337 refers to the time somehow (did this in the morning, but it could be GMT time) or it's Leetspeak...

Wednesday, July 25, 2007

Customizing the Filter Query in a List View

Filtering a list view offers a efficient way of displaying data within a list or document library.  One of its main detractors, however, is that you're limited to what the SharePoint interface allows you to filter by.  You can create complex filters using AND and OR conjunctions, but there's one main catch: the conjunctions are evaluated in order and doesn't allow any sort of order to be forced.

An Example:

Suppose I had two fields, Fruit and Quantity, in my SharePoint list and I wanted to filter a view so that I would show all combinations where I'd get a stomach ache: that would be, I guess, when Fruit = Apples and Quantity > 2, or when Fruit = Oranges and Quantity > 4.

In pseudo code, it would appears as such:

(Fruit = Apples && Quantity > 2) || (Fruit = Oranges && Quantity > 4)

The problem is that the query will not be constructed in that way.  Instead, the logic is captured as such:

(((Fruit = Apples && Quantity > 4) || Fruit = Oranges) && Quantity > 8).

Situations, such as having six apples, should appear in my new list, but don't because the Quantity > 8 overrides that for the apples.

The Fix

This is where SharePoint Designer comes to the rescue.  You can build the CAML query for the 'Where' clause appropriately to capture the logic that you are looking for.

The original Where clause will look something like this:

<Where>
  <And>
    <Or>
      <And>
        <Eq><FieldRef Name="Fruit"/><Value Type="Text">Apples</Value></Eq>
        <Gt><FieldRef Name="Quantity"/><Value Type="Number">4</Value></Gt>
      </And>
      <Eq><FieldRef Name="Fruit"/><Value Type="Text">Oranges</Value></Eq>
    </Or>
    <Gt><FieldRef Name="Quantity"/><Value Type="Number">8</Value></Gt>
  </And>
</Where>

My 'Where' clause will need to be changed to look like this:

<Where>
  <Or>
    <And>
      <Eq><FieldRef Name="Fruit"/><Value Type="Text">Apples</Value></Eq>
      <Gt><FieldRef Name="Quantity"/><Value Type="Number">4</Value></Gt>
    </And>
    <And>
      <Eq><FieldRef Name="Fruit"/><Value Type="Text">Apples</Value></Eq>
      <Gt><FieldRef Name="Quantity"/><Value Type="Number">4</Value></Gt>
    </And>
  </Or>
</Where>

Once you build your query offline, you'll need to search for and replace the old query with your new one.  Note that the XML is encoded as text, so '<', '>' characters are encoded as &lt; and &gt;, respectively.  Use your favorite notepad (Notepad++, with the XML Tools, is my personal favorite because it will do this automatically) to set your query appropriately.

Final Thoughts

Note that, if you need to change something in your view (order of fields, grouping, sorting, etc), then SharePoint will rewrite your query with what it thinks is correct.  In this example, it will replace your query with what it was before.  You'll just need to make sure that your view is set up correctly before updating the query manually.