Why do I see two copies of my Custom List Instance in a SharePoint Site?


Introduction

 

Over my years in SharePoint development I have had the following issue occur.a couple of times.

Actually back in July 2010, I posted a blog entry which solved a problem with the Manage Content and Structure page which was related to duplicate lists in a site.

  • I create a custom List with a customised List Definition which uses a schema.xml to define the List Template
  • I create a Feature which uses the customised List Definition to create a new List Template with the <ListTemplate> feature element.
  • I configure the feature to create an Instance of the list using the <ListInstance> feature Xml element,
  • Activate the feature in a SharePoint Web, click Site Actions->View All Site Content.
  • Two instances of the list appear in the View All Content page, both reference the same SharePoint list.
    Figure below shows an example of two duplicate lists in the web.
    duplicatelistitemsinweb

 

I have then always wondered what causes this?

What is interesting is that one link points to one view and the other link points to a different view, this hint was the lead to help solve the issue.

 

Solution

 

I started the investigation by digging into the SharePoint databases now quick warning, “you should not read or edit the database, doing so will leave your SharePoint installation unsupported by Microsoft!”

However, I was very careful and did not make any changes to the database.

It was one of the tables that lead me to working out why I was having these duplicate links. This table was the BuildDependencies table. I performed a

SELECT TOP 1000 [SiteId]
      ,[DirName]
      ,[LeafName]
      ,[TargetDirName]
      ,[TargetLeafName]
      ,[DirectDependency]
      ,[DeleteTransactionId]
  FROM [BuildDependencies]
  Where [DirName] LIKE ‘sites/sitename%’

Looking through the results I could see that the list had two views one called ‘ByFeatures.asppx and the other ‘AllItems.aspx’

This was correct my List Schema had defined these two views and then it dawned on me, what if SharePoint is looking at the schema.xml to work out which list page to display in the View All Content page.

So I went into my schema.xml and low and behold there was an attribute on the <View> element called DefaultView. Now both the AllItems.aspx and ByFeatures.aspx had this set to TRUE.

listschema-defaultview

 

Eureka!

So to fix this I followed this process:-

  • Updated the schema.xml <View/> element for the AllItems.aspx view
  • Modified the DefaultView attribute and set it to FALSE
  • Redeployed the solution
  • Perform an IISRESET
  • Deactivate the Feature
  • Delete the list
  • Activate the Feature to create the list

Now I only see one instance of the list in the View All Content page.

However, there is a problem with this approach and that is you lose the data in the list!

 

To Fix Existing Lists with No data loss

So we need a way to fix the lists that have already been created, seeing as the existing lists are not fixed by the schema changes then these properties must have been copied into the content database.

So to fix existing lists do the following:-

  • Browse to the list and open up the List Settings page using the Ribbon
  • Create a new View call it what you want, make sure you set it to default
  • This will reset the Default View attribute on the other views and make the new view the default view.
  • Modify the view that should really be the default view and tick the make default view checkbox. (This doesnt appear if you have multiple views with the default view set).
  • Update the view
  • Delete any views that are not needed

You should now see only one list instance in the View All Site Content page!

PowerShell to Detect Web Configuration Modification jobs


Introduction

Over the past few months I have been working on some automated SharePoint deployment scripts using Team Foundation Server and the TFS build service. As the development became more complex so did the scripts. One of the problems we had to work around was activating a number of features at the same time.

The deployment reinstalls five SharePoint solution packages, uninstalling and reinstalling all of the Features which are packaged in the solutions. Now some of these features perform custom tasks using feature receivers. For example making changes to the web.config using SPWebConfigModfications. However, one of the problems with modifying web.config using feature receivers is that if they are run on a multi server SharePoint farm then the modifications are performed using a timer job.

When you try and activate two features, one after the other, which perform the web configuration modifications you get the following error message:-

"A web configuration modification is already running"

This kills the deployment script!

Thus we needed to find a way to detect whether a web configuration modification job is in progress.

Understanding the process was made more dificult as the development machine was part of a single server SharePoint farm. With single server farms, when aa SPWebConfigModification is applied to a SPWebApplication then the modification is executed in a different manner and occurs immediately.

Anyway, after some digging about using Reflector I found an SPJobDefinition which looked like the web config modification timer job and say down and wrote the following PowerShell script.

Solution

To be able to detect whether a web config modification is running we need to see if a timer job is active.

The timer job that performs the web config modification has the name “job-webconfig-modification”.

To detect whether a web configuration is pending or running.  As web configuration operations occur against a web application. Therefore using the SPWebApplication’s SPWebService property which has two collections relating to the timer service:-

  • JobDefinitions – this contains the jobs that are pending to be run
  • RunningJobs – this contains the jobs that are currently running

Detecting whether a web configuration modification is in progress, we need to check those two collections for our “job-webconfig-modification” timer job.

The following PowerShell function, IsWebConfigModificationJobPendingOrRunning, is used to check whether a Web Configuration operation is taking place. The function takes a SPWebApplication as a parameter and returns true if the web configuration modification operation is running.

 


################################################################################################
#Function: IsWebConfigModificationJobPendingOrRunning
#Description: Checks to see if a web configuration job is pending or in progress
################################################################################################
function IsWebConfigModificationJobPendingOrRunning([Microsoft.SharePoint.Administration.SPWebApplication] $webApp)
{
Write-Host &quot;IsWebConfigModificationJobPendingOrRunning() Enter&quot;;

$bRunning=$false;
try
{
$webConfigPendingJobCount = 0;
$webConfigRunningJobCount = 0;

#if there is only one job returned then array is not created
$webConfigPendingJobs = $webApp.WebService.JobDefinitions |
Where-Object {$_.Name -like &quot;*job-webconfig*&quot;};
$webConfigRunningJobs = $webApp.WebService.RunningJobs
| Where-Object {$_.Name -like &quot;*Web.Config*&quot;};

#if there is only one job returned then array is not created - check to see if an object has been returned
#check to see if its an array if not then presume its a job.
if($webConfigPendingJobs -ne $null)
{
if($webConfigPendingJobs.GetType().BaseType.Name -eq &quot;Array&quot;)
{
$webConfigPendingJobCount = webConfigPendingJobs.Count;
}
else
{
$webConfigPendingJobCount = 1;
}
}

#if there is only one job returned then array is not created - check to see if an object has been returned
#check to see if its an array if not then presume its a job.
if($webConfigRunningJobs -ne $null)
{
if($webConfigRunningJobs.GetType().BaseType.Name -eq &quot;Array&quot;)
{
$webConfigRunningJobCount = webConfigRunningJobs.Count;
}
else
{
$webConfigRunningJobCount = 1;
}
}

Write-Host &quot;Found &quot; $webConfigPendingJobCount &quot; Pending Jobs and &quot; $webConfigRunningJobCount &quot; Running Jobs&quot;;
if(($webConfigPendingJobCount -gt 0) -Or ($webConfigRunningJobCount -gt 0))
{
$bRunning=$true;
}
else
{
$bRunning=$false;
}
}
catch
{
Write-Error &quot;IsWebConfigModificationJobPendingOrRunning Exception: $_ &quot;;
}

Write-Host &quot;IsWebConfigModificationJobPendingOrRunning() Exit : $bRunning&quot;;
return $bRunning;
}

 

Example Script

The script below shows part of the deployment script. This would be used  to loop through an array of feature names, check their scope and activate them. The script waits until the feature has activated and checks that there are no web configuration modification jobs running.

$SharePointWebApp = Get-SPWebApplication &quot;http://sharepoint&quot;;
$spfeature = &quot;Feature1&quot;;

$checkspfeatureactivation = Get-SPFeature -WebApplication $SharePointWebApp
-Identity $spfeature -ErrorAction SilentlyContinue;

if($checkspfeatureactivation -eq $null)
{
Write-Host &quot;Activating Feature: &quot; $spfeature.Name &quot; Scope: &quot; $spfeature.Scope;
Enable-SPFeature -Identity $spfeature -Url $SharePointWebApp.Url -Confirm:$false;

#check that web config job mod not running, wait if it is
do{
Start-Sleep -Seconds 2;
Write-Host &quot;Waiting for Web Config Job to be Completed&quot;;
$configJobRunning = IsWebConfigModificationJobPendingOrRunning $SharePointWebApp;
}while ($configJobRunning);

}
else
{
Write-Host &quot;Feature Already Activated: &quot; $spfeature.Name &quot; Scope: &quot; $spfeature.Scope;
}

 

I hope that helps someone who is having similar problems, I hope to add a bit more about the deployment process that I have been developing in later blog posts.

Please leave comments if you need any help or there are any problems.

Here are the actual PowerShell scripts as txt files.

SharePoint Feature Receiver token replacement only works with Guids using lower case characters


Introduction

This week I have been writing my first proper SharePoint 2010 Service Application.

Part of that solution is using a Feature Receiver to install the various components that make up a Service Application. These include:-

  • Service
  • Service Proxy
  • Service Application
  • Service Application Proxy
  • Service Instance

Tip: Andrew Connell’s chapter in the Real World SharePoint 2010 book is an excellent resource for getting the plumbing of the service application setup.

One of the issues came about at deployment time. Now that I write this, I do remember hearing about this issue before when during a SharePoint 2010 Developer Bootcamp. Of course I didn’t take enough notice and then hit the problem when I decided to update the GUID for the feature receiver.

The following error was displayed when deploying the solution:-

Error occurred in deployment step ‘Add Solution’: Failed to create receiver object from assembly “ITSP.SPMonitoringStatusPackage, Version=1.0.0.0, Culture=neutral, PublicKeyToken=de085cbd57463aa2”, class “$SharePoint.Type.edd0669b-2393-4fe6-988d-17a2De06c6e4.FullName$” for feature “ITSP.SPMonitoringStatusPackage_ITSP.SPMonitoringStatusInstaller” (ID: a5ede1b3-cbd6-4918-9f31-4322603295f5).: System.ArgumentNullException: Value cannot be null.
Parameter name: type
at System.Activator.CreateInstance(Type type, Boolean nonPublic)
at Microsoft.SharePoint.Administration.SPFeatureDefinition.get_ReceiverObject()

Screenshot:-

guid-featurereceiverdeployerror

The deployment show that any error occured because it could not create a feature receiver object from assembly “ITSP.SPMonitoringStatusPackage, Version=1.0.0.0, Culture=neutral, PublicKeyToken=de085cbd57463aa2” with the class “$SharePoint.Type.{GUID}.FullName$”.

The token, “$SharePoint.Type.{GUID}.FullName$”, should be replaced by Visual Studio as part of the build process. However this does not seem to happen with the GUID value that I was using (see below).

In this example the {GUID} value is specified against the feature receiver class using an attribute as below (please note the capital letters have been added for this example):-

guid-featurereceiveruppercase

The item that uses this GUID attribute for the Feature Receiver Class can be seen by double-clicking on the feature Visual Studio SPI object:-

featureceiver-spi

If you then look at the properties of the feature Visual Studio SPI object, you see the section as below:-

featureceiver-spi-properties

As you can see the Receiver Class has a value of:-

$SharePoint.Type.edd0669b-2393-4fe6-988d-17a2De06c6e4.FullName$

 

Solution

The issue is that upper case characters are being used and changing these to use lower case alphabetic characters for the GUID fixes the issue.

The following changes need to be made.

  1. Change the Feature Receiver’s GUID attribute.
 1: [Guid("edd0669b-2393-4fe6-988d-17a2de06c6e4")]

 

 2:     public class ITSPSPMonitoringStatusInstallerFeatureReceiver : SPFeatureReceiver

 

2. Update the Feature Receiver Visual Studio SPI object’s Receiver Class property to:-

featureceiver-spi-properties-fixed

Save all the files, rebuild, deploy and the solution is deployed successfully, hurrah!

feature-installed-successfully

 

Hope that helps.