1

I have created a timer job with following code:

namespace EmployeeDemo
{
    class DeleteEmployees : SPJobDefinition
    {
        public DeleteEmployees() : base() { }

        public DeleteEmployees(string jobName, SPWebApplication webapp)
            : base(jobName, webapp, null, SPJobLockType.ContentDatabase)
        {
            this.Title = "Delete Employees Timer Job";
        }

        public override void Execute(Guid targetInstanceId)
        {
            // Code
        }
    }
}

I then created a Site scoped feature. In its event receiver, on deactivation, I have the following code:

const string timerJobName = "Delete Employees Timer Job";
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
    DeleteJob(properties.Feature.Parent as SPSite);
}
private void DeleteJob(SPSite site)
{
    foreach (SPJobDefinition job in site.WebApplication.JobDefinitions)
    {
        if (job.Name == timerJobName)
        {
            job.Delete();
        }
    }
}

But it throws me error. From debugging I understand that the error is thrown on the line job.Delete();. The error is:

Object reference not set to an instance of an object.

This is kind of confusing to me as the statement job.Name executes flawlessly and even gets me the right timer job object. But while trying to delete the job it throws me error.

I found this question with similar problem as mine but the suggestions didn't not work for me. From this discussion I tried by writing deletion code in SPSecurity.RunWithElevatedPrivileges but it still didn't work for me.

Anyone knows why this happens and how to resolve this?

Update 1

A little more details.

NullReferenceException was unhandled by user code

Object reference not set to an instance of an object.

Here's the stack trace

   at Microsoft.SharePoint.Administration.SPConfigurationDatabase.DeleteObject(Guid id)
   at Microsoft.SharePoint.Administration.SPConfigurationDatabase.Microsoft.SharePoint.Administration.ISPPersistedStoreProvider.DeleteObject(SPPersistedObject persistedObject)
   at Microsoft.SharePoint.Administration.SPPersistedObject.Delete()
   at Microsoft.SharePoint.Administration.SPJobDefinition.Delete()
   at EmployeeDemo.Features.DeleteEmpFeature.DeleteEmpFeatureEventReceiver.DeleteJob(SPSite site)
   at EmployeeDemo.Features.DeleteEmpFeature.DeleteEmpFeatureEventReceiver.FeatureDeactivating(SPFeatureReceiverProperties properties)
   at Microsoft.SharePoint.SPFeature.DoActivationCallout(Boolean fActivate, Boolean fForce)
Community
  • 1
  • 1
Naveen
  • 6,786
  • 10
  • 37
  • 85
  • If exception is really throwed by `job.Delete()` then it should be thrown somewhere inside `Delete` method. Just because if `job` is null - exception will be thrown one line before, at `job.Name`. So you have to look into `Delete` method which you haven't shown to us. – Andrey Korneyev Mar 04 '15 at 14:28
  • @AndyKorneyev: The `Delete()` method is of the [`SPJobDefinition`](https://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spjobdefinition_members.aspx) class. It is from SharePoint API so I suppose I cannot see the source code for it, or can I? – Naveen Mar 04 '15 at 14:32
  • 1
    Well, actually you can. For example, by using .NET Reflector or other similar tool. But before exploring that source - make sure it is exactly `job.Delete` throws exception, not some line before (maybe some part of `site.WebApplication.JobDefinitions`?). For me it is very unlikely that some Microsoft API method will throw NullReferenceException without any observable reason. – Andrey Korneyev Mar 04 '15 at 14:37
  • To expand on Andy's comments: your question, if you believe it is not simply a dupe of [the canonical `NullReferenceException` question](http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it), needs to include more details. At a minimum, you need to provide complete details about the exception itself: name of the exception, and complete stack trace, in addition to the message (which you've already provided and from which we can infer the actual exception, but you should provide that anyway). – Peter Duniho Mar 04 '15 at 16:08
  • @PeterDuniho: I have added the error details as you had asked. – Naveen Mar 05 '15 at 06:44
  • Thanks. Unfortunately, without access to a repro case (including an actual SharePoint site to test with) it would be hard to know for sure what's going on. And I'm not familiar with the SP API anyway. But based on your exception and the stack trace, it looks to me as though SP already automatically removes the timer job. That is, the method that is throwing the exception is one that takes as the parameter the job object's GUID; presumably, it attempts to look that GUID up, the look-up returns null, and then the method incorrectly attempts to dereference that null object. – Peter Duniho Mar 05 '15 at 06:52
  • Technically, I'd call that a SharePoint bug. I.e. at the very least, it should be throwing a more informative exception instead of blindly assuming the GUID is valid. I don't know why the job would be removed, nor why it still shows up in the definitions collection. You might be misusing the API (e.g. is `Name` really always the same as `Title`? are you sure the job object should be valid when the feature is deactivated? etc.), or it could just be that the SP API is broken and you need a work-around. Unfortunately, I don't personally know what that might be. Sorry. :( – Peter Duniho Mar 05 '15 at 06:56

1 Answers1

0

To delete the job use powershell:

$jobToDelete = Get-SPTimerJob -WebApplication "http://intranet" -Identity "YourJobName"
$jobToDelete.Delete()

then run:

iisreset /noforce

In the configuration database you need to grant those permission to let deletion work:

use [Sharepoint_Config]
GO
GRANT EXECUTE ON [dbo].[proc_putObjectTVP] TO [WSS_Content_Application_Pools]
GRANT EXECUTE ON [dbo].[proc_putObject] TO [WSS_Content_Application_Pools]
GRANT EXECUTE ON [dbo].[proc_putDependency] TO [WSS_Content_Application_Pools]
GRANT EXECUTE ON [dbo].[proc_putClass] TO [WSS_Content_Application_Pools]
GRANT EXECUTE ON [dbo].[proc_getNewObjects] TO [WSS_Content_Application_Pools]
GRANT EXECUTE ON [dbo].[proc_dropObject] TO [WSS_Content_Application_Pools]
GO
Maurizio
  • 101
  • 7