Wednesday, December 29, 2010

Preparation for MOSS Upgrade to SharePoint 2010 - Part 1

In order to prepare for a major upgrade from MOSS 2007/WSS 3 to SharePoint 2010/SPF 4, one of the steps involved was to identify "unghosted objects" in the current Farm.  After some analysis, that list narrows down to the following types:
  • Masterpage and page layouts for Publishing Portals
  • View Forms
  • List Forms
  • Root Level files
The outer code to iterate through objects in the Farm will be something like that shown below:

try

{
//Get all Root Web Applications
SPWebApplication webApp = SPWebApplication.Lookup(new Uri(webappURL));

//Get all Sitecollections in farm
foreach (SPSite opsite in webApp.Sites)
{
try
{
foreach (SPWeb web in opsite.AllWebs)
{
try
{
GetUnghostedForms(webApp, opsite, web);
GetUnghostedFilesfromLibraries (webApp, opsite, web);
}
catch (Exception ex)
{
errors += "\n\nWEB ERRORS: " + ex.ToString();
continue;
}

finally
{
if (web != null)
web.Dispose();
}
}
//Console.WriteLine("DEBUG: site" + site.ToString());
}
catch (Exception ex)
{
errors += "\n\nSITE ERRORS: " + ex.ToString();
continue;
}


finally

{

if (opsite != null)

opsite.Dispose();

}

}

}



catch (Exception ex)

{

errors += "\n\nWEBAPP ERRORS: " + ex.ToString();
}

The methods shown above expand as follows:

static void GetUnghostedFilesfromLibraries(SPWebApplication webApp, SPSite site, SPWeb web)

{
string errors = string.Empty;

string printout = string.Empty;



#region Pages and masterpage Library


try

{

SPList masterList = web.Lists["Master Page Gallery"];

SPQuery oQuery = new SPQuery();

oQuery.Query = string.Format(".aspx.master");

SPListItemCollection colmasterListItems = masterList.GetItems(oQuery);



foreach (SPListItem currentItem in colmasterListItems)

{

try

{

SPFile file = web.GetFile(currentItem.File.Url);

if (file.CustomizedPageStatus == SPCustomizedPageStatus.Customized)

{


//add code to collect data...


}

}

catch (Exception ex)

{

errors += "\n\nPAGE ERRORS: " + ex.ToString();

continue;

}

}

}

catch (Exception ex)

{
errors += "\n\nPAGE ERRORS: " + ex.ToString();
}
#endregion
}

static void GetUnghostedForms( SPWebApplication webApp, SPSite site, SPWeb web) 
{
string errors = string.Empty;
string printout = string.Empty;


try
{

#region Root Level Files

SPFileCollection filesList = web.Files;


foreach (SPFile ifile in filesList)
{
try
{
if (ifile.CustomizedPageStatus == SPCustomizedPageStatus.Customized)
{
//code to collect data


}
}
catch (Exception ex)
{
errors += "\n\nPAGE ERRORS: " + ex.ToString();
continue;
}
}

#endregion

foreach (SPList listForms in web.Lists)
{
SPFormCollection collForms = listForms.Forms;
SPViewCollection collViews = listForms.Views;

#region List Forms

foreach (SPForm oForm in collForms)
{
try
{
if (oForm.Url.EndsWith(".aspx"))
{
SPFile file = null;
file = web.GetFile(web.Url + "/" + oForm.Url);
if (file.CustomizedPageStatus == SPCustomizedPageStatus.Customized)
{
//code to collect data


}
}
}
catch (Exception ex)
{
errors += "\n\nFORM ERRORS: " + ex.ToString();
continue;
}
}

#endregion


#region View Forms

foreach (SPView oView in collViews)
{
//exclude hidden views


if (oView.Hidden == false)
{
try
{
string url = oView.Url;


if (oView.Url.EndsWith(".aspx"))
{
SPFile file = null;
file = web.GetFile(web.Url + "/" + oView.Url);


if (file.CustomizedPageStatus == SPCustomizedPageStatus.Customized)
{


//code to collect data


}
}
}
catch (Exception ex)
{
errors += "\n\nVIEW ERRORS: " + ex.ToString();
continue;
}}
}

#endregion}
}
catch (Exception ex)
{
errors += "\n\nWEB ERRORS: " + ex.ToString();
}
}

Unghosted SharePoint objects pose an unusual challenge to the upgrade process in the sense that any default or out of the box items may replace customized ones. The end users almost always are upset when the functionality is missing and may tend to start believing that the upgrade was done poorly and their "work was lost". It will be upto the Department Managers to inform users that MOSS upgrades will require some fine tuning to maintain and restore full functionality.


So now that we have identified these customized or unghosted objects, what do we do next? This will determine on the organization structure. If you have thousands of Site Collections as we did, the responsibility will trickle down to the SCA's (Primary and Secondary Site Collection Admins). The organization will have to determine a global strategy. While code may be written to reset the definitions back to the default, in other cases, it may be necessary to recreate some of these pages once the upgrade is completed.

Wednesday, December 22, 2010

The object has been updated by another user since it was last fetched" when programmatically updating a child content type

We ran into the same issue and spent hours trying to resolve the error, and finally found a solution so I thought it would be helpful to someone else.

The scenario is a little different and actually simpler that what's described above by Djamel Chagour. We are adding a SPFieldLink to an existing SPContentType, the document library content type. We require a special column to be added to all document libraries and children of document libaries. Earlier we had tried the standard code snippet as shown below:

SPFieldLink fieldlink = new SPFieldLink(field);

libContentType.FieldLinks.Add(fieldlink);

libContentType.Update(true, false);

thisweb.Update();

- surrounded within using statements for SPweb and SPSite ofcourse. This was giving the error:

Microsoft.SharePoint.SPException: The object has been updated by another user since it was last fetched. at Microsoft.SharePoint.SPContentType.UpdateOnWeb(Boolean bPushdown, Boolean bThrowOnSealedOrReadOnly) at Microsoft.SharePoint.SPContentType.Update(Boolean updateChildren, Boolean throwOnSealedOrReadOnly) at EnterpriseTaxonomySharePointFeature.FeatureReceiver.FeatureActivated(SPFeatureReceiverProperties properties)

We changed the code to the following:

SPFieldLink fieldlink = new SPFieldLink(field);
libContentType.FieldLinks.Add(fieldlink);


//update parent


libContentType.Update(false, false);
thisweb.Update();
UpdateChildren(osite, libContentType);






private void UpdateChildren(SPSite site, SPContentType type)
{
using (SPWeb web = site.RootWeb)
{


//update children


Type.Update(true, false);
web.Update();
}
}

This prevents the SPException error. Hope this helps anyone else looking for a soultion.