Tag Archives: provisioning

SPLimitedWebPartManager.SaveChanges throws Microsoft.SharePoint.WebPartPages.WebPartPageUserException: The file is not checked out.

Got stuck on this one for a long time, more than an hour

Microsoft.SharePoint.WebPartPages.WebPartPageUserException: The file is not checked out.  You must first check out this document before making changes.   at Microsoft.SharePoint.WebPartPages.SPWebPartManager.SaveChangesCore(SPLayoutProperties layoutProperties, Boolean httpGet, Boolean saveCompressed, Boolean skipRightsCheck, Guid& newTypeId, Byte[]& newAllUsersProperties, Byte[]& newPerUserProperties, String[]& newLinks)   at Microsoft.SharePoint.WebPartPages.SPWebPartManager.SaveChangesCore(SPLayoutProperties layoutProperties, Boolean httpGet, Boolean saveCompressed, Boolean skipRightsCheck)   at Microsoft.SharePoint.WebPartPages.SPWebPartManager.SaveChangesInternal(SPLayoutProperties layoutProperties, Boolean skipRightsCheck)   at Microsoft.SharePoint.WebPartPages.SPWebPartManager.SaveChanges(Guid storageKey)   at Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager.SaveChanges(WebPart webPart)

I was using the following code to update a webpart

gWeb publishingWeb = PublishingWeb.GetPublishingWeb(webSite);
SPListItem item = publishingWeb.PagesList.GetItemByFileName(pageName);
if (item != null)
{
	SPLimitedWebPartManager webPartManager = item.File.GetLimitedWebPartManager(PersonalizationScope.Shared);
	PublishingPage publishingPage = PublishingPage.GetPublishingPage(item);

	try
	{
		if (item.File.CheckOutStatus == SPFile.SPCheckOutStatus.None)
		{
			publishingPage.CheckOut();						
		}					
		else
		{
			item.File.UndoCheckOut();
			publishingPage.CheckOut();
		}

		WebPart webpart = webPartManger.WebParts[0];
		// Do something with the webpart
		webPartManger.SaveChanges(webpart); // Now the exception is thrown
		
		
		publishingPage.Update();
		publishingPage.CheckIn(updateComment);

		if (publishingWeb.PagesList.EnableModeration)
		{
			item.File.Publish(updateComment);
			item.File.Approve(updateComment);
		}
	}
	finally
	{
		if (webPartManager != null)
		{
			webPartManager.Dispose();
		}
	}
}

A quick google reveals quite a lot of other people stumped with this problem. Why is it saying the file is not checked out, the lines above it make sure it’s always checked out to the user running the code. Turns out it’s quite a simple fix. Don’t instantiate the SPLimitedWebPartManager until your done making sure the page is checked out!

Working code

gWeb publishingWeb = PublishingWeb.GetPublishingWeb(webSite);
SPListItem item = publishingWeb.PagesList.GetItemByFileName(pageName);
if (item != null)
{
	SPLimitedWebPartManager webPartManager = null;
	PublishingPage publishingPage = PublishingPage.GetPublishingPage(item);

	try
	{
		if (item.File.CheckOutStatus == SPFile.SPCheckOutStatus.None)
		{
			publishingPage.CheckOut();						
		}					
		else
		{
			item.File.UndoCheckOut();
			publishingPage.CheckOut();
		}

		// Now we're certain the page is checked out, grab the web part manager.
		webPartManger = item.File.GetLimitedWebPartManager(PersonalizationScope.Shared);

		WebPart webpart = webPartManger.WebParts[0];
		// Do something with the webpart
		webPartManger.SaveChanges(webpart); // Now the exception is thrown
		
		
		publishingPage.Update();
		publishingPage.CheckIn(updateComment);

		if (publishingWeb.PagesList.EnableModeration)
		{
			item.File.Publish(updateComment);
			item.File.Approve(updateComment);
		}
	}
	finally
	{
		if (webPartManager != null)
		{
			webPartManager.Dispose();
		}
	}
}

Notice that we assign the value of the web part manager after we make sure the page is checked out. Hopefully this saves someone a couple of missing hours i’ll never get back ๐Ÿ™‚

Tagged , , ,

Provisioning a Web Part with a predefined ID in your onet.xml of element manifest.

From time to time you might want to provision your WebParts using the CAML markup and then modify them in a feature later on. Most examples on the web find the webpart based on itโ€™s title. i.e.

foreach(Webpart webpart in webpartManager.WebParts)
{
   if(webpart.Title == "Title I'm expecting")
   {
       // Do something with the webpart
       webpart.AuthorizationFilter = "";
       webpartManager.SaveChanges(webpart);
   }
}

However you can specify the ID of a web part in your onet.xml / element manifest like so:

 <View List="Lists/MyList" BaseViewID="1" DisplayName="Counter Parties" Name="List Nmae" RecurrenceRowset="TRUE" WebPartZoneID="Header" WebPartOrder="1">
        <![CDATA[
               <WebPart xmlns="http://schemas.microsoft.com/WebPart/v2">
                    <Assembly>Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
                    <TypeName>Microsoft.SharePoint.WebPartPages.ListViewWebPart</TypeName>
                    <Title>MyList - Workflow Users</Title>
                    <DetailLink>~Site/Lists/MyList/AllItems.aspx</DetailLink>
                    <Description>Use this list to store ... information.</Description>
                    <ID>g_45C819FD_FC4C_44e1_81DD_3AE4FCC34D37</ID>
               </WebPart>
            ]]>
      </View>

Create a new Guid replace the hyphens with underscores and add a “g_” to the beginning of the string g_45C819FD_FC4C_44e1_81DD_3AE4FCC34D37.

Now we can reference the web part in your feature receiver using the indexer property, which is I think you’ll agree much more elegant and less error prone:

Webpart = webpartManager["g_45C819FD_FC4C_44e1_81DD_3AE4FCC34D37"]
// Do something with the webpart
webpart.AuthorizationFilter = "";
webpartManager.SaveChanges(webpart);
Tagged , , ,