Sunday, July 31, 2011

SharePoint 2010 List Item Event Receiver - Native Stack Error 0x81020089

When creating List Item Event Receivers, we added the ItemDeleting event to prevent List Items from being deleted:

public override void ItemDeleting(SPItemEventProperties properties)
{
    properties.Cancel = true;
    properties.Status = SPEventReceiverStatus.CancelWithRedirectUrl;
    properties.ErrorMessage = "Bugs can only be resolved not deleted!";

    //You may also redirect to a custom error URL page:
    //SPUtility.Redirect(web.Url + Constants.ERROR_PAGE_URL + errorMessage, SPRedirectFlags.DoNotEndResponse, HttpContext.Current);
}

You would think that the above piece of code will show an appropriate validation message while deleting a list item, but instead it throws a native call stack error.

We identified that these code lines do not work very well with List Item event receivers:

properties.Cancel = true;  and
properties.Status = SPEventReceiverStatus.CancelWithRedirectUrl;

As a result we see a Native Stack Error Message:

We modified the ItemDeleting Event receiver code and it started working fine:

public override void ItemDeleting(SPItemEventProperties properties)
{
    properties.Status = SPEventReceiverStatus.CancelNoError;
    properties.ErrorMessage = "Bugs can only be resolved not deleted!";

     //You may also redirect to a custom error URL page:
    //SPUtility.Redirect(web.Url + Constants.ERROR_PAGE_URL + errorMessage, SPRedirectFlags.DoNotEndResponse, HttpContext.Current);
}


Elements.xml file for the List Item Event Receiver is as follows:

<?xml version="1.0" encoding="utf-8" ?> 
- <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
- <Receivers ListTemplateId="100">
- <Receiver>
  <Name>CustomItemDeleting</Name> 
  <Type>ItemDeleting</Type> 
  <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly> 
  <Class>SharePointFix.Project.ItemDeletingEvent</Class> 
  <SequenceNumber>10001</SequenceNumber> 
  </Receiver>
  </Receivers>
  </Elements>

Receiver ListTemplateId = 100, ensures that the validation works for both Pages library and Custom SharePoint Lists.

Friday, July 22, 2011

Powershell script to deploy multiple solutions (.wsp) to your SharePoint 2010 web application

The Powershell script below iterates through each .wsp files in your physical folder, installs and deploys them globally into all web-applications thus automating the solution deployment process.

Copy the PowerShell scriptlet below and paste it in a notepad and save it with a .ps1 extension in any of the directories in your hard disk.

NOTE: Do not forget to place all your solution files i.e..wsp files in the same directory as your .ps1 directory.
======================================================================

Add-PsSnapin Microsoft.SharePoint.PowerShell

#Do not modify anything in the script from here onwards
function Get-ScriptDirectory
{
 $Invocation = (Get-Variable MyInvocation -Scope 1).Value
 Split-Path $Invocation.MyCommand.Path
}

function Deploy-Solution{
param(
[string]$physicalPath,
[string]$name)

$SolutionName = $name
$SolutionPath = Join-Path ($physicalPath) $SolutionName
echo "Extracting information from $physicalPath"

#Admin service
$AdminServiceName = "SPAdminV4"
$IsAdminServiceWasRunning = $true;

if ($(Get-Service $AdminServiceName).Status -eq "Stopped")
{
    $IsAdminServiceWasRunning = $false;
    Start-Service $AdminServiceName
   Write-Host 'SERVICE WAS STOPPED, SO IT IS NOW STARTED'
}

#Uninstall
Write-Host 'UNINSTALLING SOLUTION ...'

$Solution = Get-SPSolution | ? {($_.Name -eq $SolutionName) -and ($_.Deployed -eq $true)}

if ($Solution -ne $null)
{
    if($Solution.ContainsWebApplicationResource)
    {
        Uninstall-SPSolution $SolutionName -AllWebApplications -Confirm:$false
    }
    else
    {
        Uninstall-SPSolution $SolutionName -Confirm:$false
    }
}

while ($Solution.JobExists)
{
    Start-Sleep 2
}

Write-Host 'SOLUTION HAS BEEN UNINSTALLED SUCCESSFULLY.'

Write-Host 'REMOVING SOLUTION ...'

if ($(Get-SPSolution | ? {$_.Name -eq $SolutionName}).Deployed -eq $false)
{
    Remove-SPSolution $SolutionName -Confirm:$false

Write-Host 'SOLUTION HAS BEEN REMOVED SUCCESSFULLY.'
}

Write-Host 'ADDING SOLUTION ...'

Add-SPSolution $SolutionPath  | Out-Null

Write-Host 'SOLUTION HAS BEEN ADDED SUCCESSFULLY.'

Write-Host 'DEPLOYING SOLUTION ...'

$Solution = Get-SPSolution | ? {($_.Name -eq $SolutionName) -and ($_.Deployed -eq $false)}

#use '-force' paramater to install all commands in this if statement

if(($Solution -ne $null) -and ($Solution.ContainsWebApplicationResource))
{
Install-SPSolution $SolutionName –AllwebApplications -GACDeployment -Force -Confirm:$false
}
else
{
Install-SPSolution $SolutionName -GACDeployment -Force -Confirm:$false
}

while ($Solution.Deployed -eq $false)
{
    Start-Sleep 2
}

Write-Host 'SOLUTION HAS BEEN DEPLOYED SUCCESSFULLY.'

if (-not $IsAdminServiceWasRunning)
{
    Stop-Service $AdminServiceName
}
}

#Get Current Physical Path
$currentPhysicalPath = Get-ScriptDirectory

#Iterate through all .wsp files in the current Physical Path to deploy solution
get-childitem $currentPhysicalPath -include *.wsp -recurse | foreach ($_) {Deploy-Solution $currentPhysicalPath $_.name}

#Remove SharePoint Snapin
Remove-PsSnapin Microsoft.SharePoint.PowerShell

Echo Finish

====================================================================


Automate the above .ps1 script as a batch utility, Copy and paste code below and save it with a .bat file extension, change the script file name in the highlighted yellow section below to your .ps1 name.

cd /d %~dp0
powershell -noexit -file ".AutomateDeploymentScript.ps1" "%CD%"
pause

Run the batch file and enjoy the automated deployment process:)

Tuesday, May 17, 2011

SharePoint Central Administration Content Database in Suspect Mode

What will be your first reaction when your Central Administration in SharePoint 2010 stops abruptly and its Content/Config database switches itself automatically to Suspect mode for no apparent reason, that too after a very stressful and super-hard working day.

Common human reaction is to get scarred, pissed-off, drop the F-bombs on SharePoint 2010, drink lots of coffee, get irritated and shout on friends and family... :)

I checked the ULS logs, Event Viewer logs, tried Application Pool recycles, Website Start/Stops, IIS Resets, even re-booted the server, even ran the SP 2010 Config Wizard. Sadly, none of them worked. By now I started thinking that my SP 2010 farm is corrupt and needs to be re-configured/re-installed from scratch. A very painful thought in itself.

But as I further researched on this weird content database suspect issue, found this post on the forum which got me started: http://social.msdn.microsoft.com/forums/en-US/sqldisasterrecovery/thread/48cf82c9-2179-46f3-b009-11416a90d248/

However, I had to do a lot of R&D to get the actual SQL commands working.

Go to your SQL Server and ensure either your Central Admin Content Database or Config Database, if it is in Suspect mode, then this post is for you, see snapshot below:







So either a Central Admin Content database or a Config database can abruptly go into the suspect mode without any apparent logical reason. In my case, SharePoint Central Admin Content Database went into the Suspect mode.

To resolve the issue, follow steps in the following order as mentioned:

1. Go to your MSSQL\Data files that reside under: C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA


2. Identify your Central Admin Content Database name in my case it got screwed up and was in the suspect: mode: so this is my content database name SharePoint_AdminContent_38c5cc2d-aeec-4dc2-b7a5-65457250ae2c


NOTE: Please take a backup of the corrupted .mdf and .ldf files, before following other steps.

3. Open your SQL Server Management Studio ->, New Query and it opens up your SQL Query editor, copy and paste the query below and change the highlighted to your database name:

Use master

--Verify whether Database has any issues
EXEC sp_resetstatus "SharePoint_AdminContent_38c5cc2d-aeec-4dc2-b7a5-65457250ae2c.mdf"

---Alter database and put it on Emergency Mode
ALTER DATABASE "SharePoint_AdminContent_38c5cc2d-aeec-4dc2-b7a5-65457250ae2c" SET EMERGENCY
DBCC checkdb('SharePoint_AdminContent_38c5cc2d-aeec-4dc2-b7a5-65457250ae2c')

--Set the database in the Single User mode
ALTER DATABASE "SharePoint_AdminContent_38c5cc2d-aeec-4dc2-b7a5-65457250ae2c" SET SINGLE_USER WITH ROLLBACK IMMEDIATE

--Repair the database and allow data loss
DBCC CheckDB('SharePoint_AdminContent_38c5cc2d-aeec-4dc2-b7a5-65457250ae2c',REPAIR_ALLOW_DATA_LOSS)

--Set the database back to Multi-User mode
ALTER DATABASE "SharePoint_AdminContent_38c5cc2d-aeec-4dc2-b7a5-65457250ae2c" SET MULTI_USER

--Ensure Database is reset
EXEC sp_resetstatus 'SharePoint_AdminContent_38c5cc2d-aeec-4dc2-b7a5-65457250ae2c'

Execute all the commands in your SQL Query Editor and there you go, Go back to your SQL Management Studio and you can see that the (Suspect) mode issue against the Content/Config database is fixed and the database got fully repaired and restored.

To verify the same, hit your Central Administration and it starts working just fine...

NOTE: This post is true for any Content Database/Config Database in your SharePoint 2010 farm and not subject to only the Central administration web application. It will work equally well, if any of your current Web Application/Site Collection Content database gets corrupted and switches into the Suspect mode.

I hope it helps,

Tuesday, May 10, 2011

Powershell script to Enable Developer Dashboard

Here is the Powershell script to Enable Developer Dashboard in SharePoint 2010

Add-PsSnapin Microsoft.SharePoint.PowerShell
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Administration")

##Turn On: for on-Demand Mode

$service = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
$addsetting =$service.DeveloperDashboardSettings
$addsetting.DisplayLevel = [Microsoft.SharePoint.Administration.SPDeveloperDashboardLevel]::OnDemand
$addsetting.Update()

##Turn On

$service = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
$addsetting =$service.DeveloperDashboardSettings
$addsetting.DisplayLevel = [Microsoft.SharePoint.Administration.SPDeveloperDashboardLevel]::On
$addsetting.Update()

##Turn Off

$service = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
$addsetting =$service.DeveloperDashboardSettings
$addsetting.DisplayLevel = [Microsoft.SharePoint.Administration.SPDeveloperDashboardLevel]::Off
$addsetting.Update()


Mode of developer dashboard:
On – creates everytime the output at the end of the page content
Off – switch off developer dashboard and nothing is rendered
OnDemand – creates a DeveloperDashboard icon to make dashboard output visible as needed

Developer Dashboard is visible on the upper right hand corner:















Thursday, May 5, 2011

Find the Role/Permissions of a currently logged in user in SharePoint 2010

This method below, tries to Find Role/Permission for the currently logged-in user using SPRoleAssignment and SPRoleDefinition objects. Check it out to learn more about the object model for identifying roles using the SPRoleType enumerator

public void FindRolesForCurrentlyLoggedInUser(SPWeb web, SPUser user)
{
bool IsApprover = false;
bool IsReader = false;
bool IsDirectPermission = false;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(siteID))
{
using (SPWeb web = site.OpenWeb(webID))
{
//Check all Groups in the Current Web
foreach (SPGroup group in web.Groups)
{
try
{
//Check If Currently Logged In User has permissions in the all Web Groups
if (group.Users[user.LoginName].ID.ToString().Equals(user.ID.ToString()))
{
//Get Role Assignments
SPRoleAssignment currentUserRole = web.RoleAssignments.GetAssignmentByPrincipal(group as SPPrincipal);

//Go through all Role Definition Bindings
foreach (SPRoleDefinition role in currentUserRole.RoleDefinitionBindings)
{
//Check If Role Type == Reader - Do something
if (role.Type.Equals(SPRoleType.Reader))
{
}
//Administrators access - Full Control - Do something
else if (role.Type.Equals(SPRoleType.Administrator))
{
}
//Contributor access - Contribute - Do something
else if (role.Type.Equals(SPRoleType.Contributor))
{
}
//Web Designer access - Design rights- Do something
else if (role.Type.Equals(SPRoleType.WebDesigner))
{
}
//Limited access - Do something
else if (role.Type.Equals(SPRoleType.Guest))
{
}
//No access on Current Web- Do something
else if (role.Type.Equals(SPRoleType.None))
{
}
}
}

//Get Role Assignments for Current User - If he has been directly assigned permissions
try{SPRoleAssignment directPermission = web.RoleAssignments.GetAssignmentByPrincipal(user as SPPrincipal);}
catch(Exception){/*Best attempt to catch Exceptions*/}
}
catch (Exception)
{
/* Best Attempt to find the User In the Group. Do not throw any exception if a user does not exist in the Group */
}

}
}
}
});
}