Friday, February 20, 2009

Cascading dropdown lists and error 401

Until recently we successfully used the tip from Ishai Sagi on cascading lists, but suddenly our users reported getting a error when trying to use the drill down Master-Detail dropdown lists.

Looking at the IIS log we discovered the call to owssrv.dll was done anonymous and resulted in an error 401. With good help from a consultant from Key2Know we found that the issue was related to a loopback check security update on Windows Server 2003 SP1. The solution was found on http://support.microsoft.com/kb/896861 where you can read more about this issue.

We implemented solution 1 on our Web Front Ends and this resolved the issue.

Wednesday, February 11, 2009

Creating logging for workflows and eventhandlers

When dealing with workflows you often have the abillity to do debugging in your DEV environment, but when it comes to eventhandlers things get a litle more grumsy. And fully testing every possible scenario and user inputs is impossible so one day your code is gonna break and if you haven't made a log, you don't know why...

I use the same logging feature and logging place for all of our workflows and our one and only Construction Kit Eventhandler (more on that another day). It's fairly simple, but functionally enough to keep me going.

So in the terms of C#:
  • Make two global variables

    public int i = 0;
    StringBuilder MyStringBuilder = new StringBuilder();

  • Create two functions

    public void AddToLog(string msg)
    {
    MyStringBuilder.AppendLine(DateTime.Now.ToLongTimeString() + ":" + i.ToString() + "=" + msg);
    }

    public void WriteLog()
    {
    try
    {
    AddToLog("Log ended at i = " + i.ToString());
    SPList SetupList = web2.Lists["Logs"]; //use global SPWeb here or hardcode
    SPListItem myItem = SetupList.Items.Add();
    myItem["Title"] = myContentType;
    myItem["Log"] = MyStringBuilder;
    myItem.Update();
    SetupList.Update();
    }
    catch (Exception Ex)
    {
    //Even logging can fail so you may want to take some action here
    }
    }

  • In your code place a code counter and code logging like this:

    AddToLog("ReadSettings started...");
    i = 1;
    myUrl = workflowProperties.WebUrl.ToString();
    i++;
    AddToLog(" Url: " + myUrl);
    i++;
    Etc...

    The code counter 'i' gives you the option of pin pointing exactly at which line of code the error occurred.

  • At the end of your code execution and at your global error handling code ensure to get the log written:

    WriteLog();

The Logs list should contain two columns, 'Title' as Single line of text and 'Log' as Multiple lines of text (plain text).

Now you can hardcode your logging destination into the WriteLog function or you can setup a global SPWeb object (remember to dispose it at the end of the code execution) like I do. My code look something like this:

string myUrl = workflowProperties.WebUrl.ToString();
i++;
int startcmd = myUrl.IndexOf("//");
i++;
int startval = myUrl.IndexOf("/", startcmd + 2);
if (startval == -1) startval = myUrl.Length;
i++;
SPSite objSite = new SPSite(myUrl.Substring(0, startval).ToLower().Replace("corporate", "collaboration") + "/SubFolder/Settings");
i++;
web2 = objSite.OpenWeb();
i++;

The .Replace("corporate", "collaboration") trick is about having two different webs served by the same code, but only having one place to host the logging, e.g. at http://collaboration/SubFolder/Settings/Logs

Obviously our logging code also deals with log archiving, success or failiure logging as well as notification of sys admins, but for the sake of simplicity this is the starting point.

Display the version number on your InfoPath form

Tired of not really knowing if the InfoPath form you're looking at is the latest version?

Here's a simple trick to display the info.


  • On your form find a suitable place to add a textbox (I place mine at the bottom, right corner)
  • In the new textbox property, click the Fx button and insert the following in the formula box:
    concat(substring-before(substring-after(processing-instruction()[local-name(.) = "mso-infoPathSolution"]; 'href="'); '"'); " template with form version "; substring-before(substring-after(processing-instruction()[local-name(.) = "mso-infoPathSolution"]; 'solutionVersion="'); '"'))
  • Now you can format the textbox with text color, size (use 'auto' as width) and position.

I found parts of this somewhere on the net, so don't blame me if it works :-)

InfoPath properties and SharePoint columns

I just hate it when there's no logic explanation!

Had an InfoPath form, published to SharePoint, needed to add some new fields, created the matching Site Columns, promoted the fields to the new columns, republished - everything looked good on our TEST server and then I did the same thing in our PROD environment: NoGo.

Yes, the form was published ok. The resulting xml documents had the changes, but the SharePoint Site Columns didn't reflect the changes. I searched logs, checked for misspells, googled for a day - nothing! It all looked correct, but it didn't work. (Actually not quite correct cause the columns where now properties of the ListItem and therefore didn't belong to the document).

Finally I found a fellow blogger that in turn had found some other bloggers and to make it short, here's the link: http://arichterwork.blogspot.com/2008/03/infopath-property-promotion-woes.html

All credit goes to these guys, but let me just sumerize the workaround (it's not a solution, nor an explanation):
  1. Using Central Admin, Applications, InfoPath, you need to deactivate the faulting form from all of the Site Collections it has been activated on.
  2. While deactivated, upload a new version of the form.
  3. Reactivate the form to the Site Collections where it is needed.

This made my InfoPath fields or properties work and I got the reflecting values on my SharePoint columns.

It looks like this bug occurs when you have republished your InfoPath form several time, but I really hope it will be fixed soon.