Friday, September 28, 2007

Workaround - "Error" in navigation when creating a publishing site from code

Since I started working with sharepoint 2007 I was puzzled by this bug, and recently I asked more people how said they have that too. The problem happens when you use the API to create a site out of a template that has the publishing feature activated in it. The site is created ok, but the first user to open the site will see a very odd tab and quick-launch:






So far, I have no explanation, but I have a workaround. Make a call to the site in the code. I know - this adds process time and resources, but it beats having your users ask you about the "error tab".
In your code, add the following function, and call it just after the site creation code:



public static void OpenUrl(string url)
{
try
{
HttpWebRequest request = (HttpWebRequest)
WebRequest.Create(url);
request.UseDefaultCredentials = true;
HttpWebResponse response = (HttpWebResponse)
request.GetResponse();
}
catch(Exception ex) {
//do something with the error
}
}


Here is an example how to use this function:



public static void CreateSite(SPWeb parentWeb)
{
try
{
//get the template for the site using the GetWebTemplate function I wrote
SPWebTemplate template =
SharePointFunctions.GetWebTemplate(parentWeb,
this.SiteTemplateName,
ConfigVariables.SitesLCID);
//create the site using the class properties
newWeb = parentWeb.Webs.Add(this.ShortName,
this.SiteTitle,
this.SiteDescription,
ConfigVariables.SitesLCID,
template,
false,
false);
OpenSiteHomePage(newWeb.Url);
}
catch(Exception ex) {
//do something with the error
}
}









Wednesday, September 26, 2007

Joined BlogRush

Not sure if that will make any difference, but I joined this site (BlogRush) in hope of getting more visitors. I will let you know if it works!

Back from vacation

Hello my readers!

You may have noticed I didn't blog this month, and that was because I was on my annual leave, visiting my family and friends in hot Israel!

I took time in the trip to present at the Israeli SharePoint User Group in Microsoft Israel, and I was very surprised to see how many people turned up! We had more than 50 people there, a lot of past clients and past collegues.



Here is a picture of the lowest sharepoint expert in the world (me floating in the dead sea -416 meters below sea level! to get lower, you need to go on a submarine):





And here are a couple of pictures I took that I think would make great desktop backgrounds:




































Tuesday, September 04, 2007

Just for me - excel macro to generate an XML

If you are here for a sharepoint tip, disregard this post- I am posting this to myself so I will not lose this code. Basically, it is an excel macro that genenrates an xml file from the current sheet. If you do want to use it, add a reference to microsoft xml in the VBA environment, and paste the code below to a module.
There are many way to improve it, but I just wrote this to quickly achieve a small task that I needed done.

Sub makeXml()
    ActiveCell.SpecialCells(xlLastCell).Select
    Dim lastRow, lastCol As Long
    lastRow = ActiveCell.Row
    lastCol = ActiveCell.Column
    
    Dim iRow, iCol As Long
    
    Dim xDoc As New DOMDocument
    Dim rootNode As IXMLDOMNode
    Set rootNode = xDoc.createElement("Root")
    Dim rowNode As IXMLDOMNode
    Dim colNode As IXMLDOMNode
    
    'loop over the rows
    For iRow = 2 To lastRow
        Set rowNode = xDoc.createElement("Row")
        'loop over the columns
        For iCol = 1 To lastCol
            If (Len(ActiveSheet.Cells(1, iCol).Text) > 0) Then
                Set colNode = xDoc.createElement(GetXmlSafeColumnName(ActiveSheet.Cells(1, iCol).Text))
                
                colNode.Text = ActiveSheet.Cells(iRow, iCol).Text
                rowNode.appendChild colNode
            End If
        Next iCol
        rootNode.appendChild rowNode
    Next iRow
    xDoc.appendChild rootNode
    xDoc.Save ("c:\temp\temp.xml")
    set xDoc = Nothing
    
End Sub
Function GetXmlSafeColumnName(name As String)
    Dim ret As String
    ret = name
    ret = Replace(ret, " ", "_")
    ret = Replace(ret, ".", "")
    ret = Replace(ret, ",", "")
    ret = Replace(ret, "&", "")
    ret = Replace(ret, "!", "")
    ret = Replace(ret, "@", "")
    ret = Replace(ret, "$", "")
    ret = Replace(ret, "#", "")
    ret = Replace(ret, "%", "")
    ret = Replace(ret, "^", "")
    ret = Replace(ret, "*", "")
    ret = Replace(ret, "(", "")
    ret = Replace(ret, ")", "")
    ret = Replace(ret, "-", "")
    ret = Replace(ret, "+", "")
    
    GetXmlSafeColumnName = ret
End Function

Monday, September 03, 2007

The security validation for this page is invalid.

When writing code for sharepoint, you may encounter the error "The security validation for this page is invalid. Click Back in your Web browser..." and so on. A lot has been written on this, with many different people touting different solutions. For example SpiderWool says to turn on security validation for the application.
This is not recommended, and not required as one of the comments said - all you need to do before you update the list item or web object is to set "AllowUnsafeUpdates" to true for the SPWeb and SPSite objects.
But some of the other comments in the same post complain that it didn't help them. Well, most probably the reason is that they created the SPWeb or SPSite objects in another function and then tried to update an object that was returned from the function. Here are two examples of the same code, where one will work and the other will not:
Bad Example:
The code calls a function to get the list, where the SPWeb and SPSite are created in the function.

using (SPSite site = new SPSite(parentSiteUrl))
{
        site.AllowUnsafeUpdates = true;
        using (SPWeb web = site.OpenWeb())
        {
            web.AllowUnsafeUpdates = true;
            SPList list = GetList("mylist");
            _listItem = clientsList.Items.Add();
            _listItem["Title"] = "test";
            _listItem.Update();                    }
        }
}
private SPList GetList(string name)
{
   using (SPSite site = new SPSite(parentSiteUrl))
   {
        site.AllowUnsafeUpdates = true;
        using (SPWeb web = site.OpenWeb())
        {
            web.AllowUnsafeUpdates = true;
            SPList list = web.Lists["mylist"];
            return list;
        }
   }
}

Good Example:
Loading the SPSite and SPWeb object only once and using them to get the list.

using (SPSite site = new SPSite(parentSiteUrl))
{
        site.AllowUnsafeUpdates = true;
        using (SPWeb web = site.OpenWeb())
        {
            web.AllowUnsafeUpdates = true;
            SPList list = web.Lists["mylist"];
            _listItem = clientsList.Items.Add();
            _listItem["Title"] = "test";
            _listItem.Update();                    }
        }
}