2
votes

I am using this tutorial as example to create a timer job.

Here is my timer job code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint;

namespace CalcAnnualConsumptionTotals
{
    public class GroupAnnualConsumption : SPJobDefinition
    {
        public GroupAnnualConsumption() : base() {} // <-- public default constructor

        public GroupAnnualConsumption(string jobName, SPService service, 
               SPServer server, SPJobLockType lockType)
               : base(jobName, service, server, lockType)
        {
            this.Title = "Group Annual Consumption";
        }

        public GroupAnnualConsumption(string jobName, SPWebApplication webapp)
            : base(jobName, webapp, null, SPJobLockType.ContentDatabase)
        {
            this.Title = "Group Annual Consumption";
        }

        public override void Execute(Guid targetInstanceId)
        {
            .....
        }
    }
}

As you can see I have the default public constructor but when I try to deploy this it shows me error of:

Error occurred in deployment step 'Retract Solution': CalcAnnualConsumptionTotals.GroupAnnualConsumption cannot be deserialized because it does not have a public default constructor

When the first time I got this error I had actually forgotten to add default constructor. But even after adding it is showing me the error. I thought that my initial attempt would be partially successfull resulting in deployment. But I can't find it even via Central Administration or Get-SPTimerJob.

Any ideas why this error is coming up.

4

4 Answers

2
votes

Okay, here was the problem. As I already mentioned in the question

...When the first time I got this error I had actually forgotten to add default constructor....

So what happened was that the solution got deployed on SharePoint but the error came at first time also (can't recollect if it was the same error or not). Next time when I rectified the error and tried to deploy, it showed me the error:

Error occurred in deployment step 'Retract Solution': CalcAnnualConsumptionTotals.GroupAnnualConsumption cannot be deserialized because it does not have a public default constructor

Retract Solution was the keyword here. When SharePoint tried to deploy updated solution it had to retract the old one but could not and because of error in (old) solution.

So I went to Manage Farm Solutions in Central Administration and remove the solution. Then when I deployed, it worked.

1
votes

The above didn't work for me, but I did find a solution and wanted to post it here in case anyone else runs into the same situation.

In my case, I was not able to uninstall via the Manage Farm Solutions page, at least, not initially.

I had to first fix the code by adding a default constructor. Then I had to GAC the file using gacutil. I then reset IIS using iisreset /restart. Only then was I able to request that the solution be retracted in the Manage Farm Solutions page.

Unfortunately, then it just sat there. So, to fix that problem I did:

  1. stsadm -o enumdeployments
  2. stsadm -o canceldeployment -id "the guid value displayed in step 1"
  3. via powershell: remove-spsolution -Identity solutionname.wsp -force
  4. iisreset /restart (you may get an error during redeploy that the solution is still installed unless you bounce iis manually)

Then I was able to redeploy and get back to working.

0
votes

From here:

You are also required to call either the web service association constructor or the service application association constructor from one of your timer job definition’s constructors. Remember, your timer job must be associated with one of these two entities. The only time that an association can be created is from the constructors on the SPJobDefinition class, so one of your constructors has to be associated with a call down to the appropriate base constructor.

It appears you need to set one of those two properties from your default constructor. It would be easiest if you can pass the values to one of your other constructors.

Edit: To clarify, I think passing the jobname parameter to the base constructor would suffice. If you don't have access to that value (is it hard-coded, or in a config file?) you may have to re-structure things.

That said, I've never worked with Sharepoint, so I could be off base.

0
votes

It seems the "old version" of SharePoint Job is still up and running.

When you deploy a SharePoint Job, SharePoint Timer service has to be restarted.

How to restart SharePoint Timer service via PowerShell

function Restart-SPTimerV4()
{
  [array]$servers= Get-SPServer | ? {$_.Role -eq "Application"}            
  $farm = Get-SPFarm            
  foreach ($server in $servers)            
  {            
     Write-Host "Restarting Timer Job on $server"                                      
     $Service = Get-WmiObject -Computer $server.name Win32_Service -Filter "Name='SPTimerV4'"                        
     if ($Service -ne $null)                         
     {                             
        $Service.InvokeMethod('StopService',$null)            
        Start-Sleep -s 7            
        $service.InvokeMethod('StartService',$null)                             
        Start-Sleep -s 7            
        Write-Host "Timer Job successfully restarted on $server"                        
     }             
     else            
     {            
        write-host -ForegroundColor Yellow "Could not find SharePoint 2010 Timer Service on $server"            
     }            
  }
}