Timer Jobs and SharePoint Deployment

While deploying a SharePoint solution to my development environment with PowerShell I got this surprising error:

Failed to create receiver object from assembly "****", class "****.EventReceiver" for feature "****" (ID: ****).: System.ArgumentNullException: Value cannot be null

When trying to redeploy the solution I got this error (which is expected):

A feature with ID **** has already been installed in this farm.  Use the force attribute to explicitly re-install the feature.

The last error occurs because some features were installed before the original deployment error occurred. An efficient way to uninstall these features is to retract the solution (even though it is not deployed):

stsadm -o retractsolution –name ****.wsp -url http://**** -immediate

If this does not work you can use the -local parameter instead of –immediate and run the command on all servers in the farm. But typically it works fine on a single server farm.

Redeploying the solution gives now this error message:

Failed to load receiver assembly "****" for feature "****" (ID: ****).: System.IO.FileNotFoundException: Could not load file or assembly ‘****’ or one of its dependencies. The system cannot find the file specified.

I found this very confusing to begin with because the actual error message changes. After some digging into the problem I determined that there is nothing wrong with the assembly, its references or the feature event receiver class – which is the original error message. The reason for the failure is that the updated assembly that contains a new feature event receiver is not being loaded by the SharePoint Timer Job. Then I tried the following:

  1. Stopping and starting the timer job (net start sptimerv4 and net stop sptimerv4)
  2. Clearing the SharePoint Configuration Cache
  3. Rebooting the server (ok, getting desperate)
  4. Disabling all SharePoint timer jobs that are in the same assembly that causes the failure
  5. Deleting all SharePoint timer jobs that are in the same assembly that causes the failure with PowerShell (Get-SPTimerJob | ? { $_.Name.StartsWith("****") } | % { $_.Delete() }

It turns out that in my situation the following sequence solves the deployment problem:

  1. Retract the solution package (as described above)
  2. Delete all timer jobs that are in the same assembly that causes the failure
  3. Clear the SharePoint Configuration Cache
  4. Deploy the solution package

What I learned from this is that you should either place SharePoint timer jobs in a separate assembly that will never contain feature event receivers or update the assembly version of the assemblies containing SharePoint timer jobs. The latter might cause some other issues in case the solution uses hard-coded references to that assembly such as in user controls (ASCX), HTTP handlers (ASHX) or custom web.config sections. This can be avoided in most situations with the new token “$SharePoint.Project.AssemblyFullName$” in SharePoint 2010 to reference the current assembly.