Question

I Have weird problem intalling custom timer job definition to specific webapplication.

Environment is 2x wfe + 1x application server.

Development and staging works fine (single server boxes)

...method 'FeatureActivated' for feature '6ae97a43-a342-4f66-8416-2b492c88f896' threw an exception: Microsoft.SharePoint.SPException: (this is my custom error ->**Error occurred while installing Timer Job Definition) - **Error obtaining reference to Site - at MyTimerJob.TimerJobInstaller.FeatureActivated(SPFeatureReceiverProperties properties) at MyTimerJob.TimerJobInstaller.FeatureActivated(SPFeatureReceiverProperties properties) at Microsoft.SharePoint.SPFeature.DoActivationCallout(Boolean fActivate, Boolean fForce)

This happens when I try to activate my timer job feature. It does the same if I activate it from UI or from STSADM...

Here is the receiver code and feature.xml

public override void FeatureActivated(SPFeatureReceiverProperties properties)
    {
        try
        {
            const string featureGuid = "6ae97a43-a342-4f66-8416-2b492c88f896";
            const string schedulePropertyName = "ScheduledRunTime";  

            // register the the current web
            SPWebApplication webApp = properties.Feature.Parent as SPWebApplication;

            if (webApp == null)
            {
                throw new SPException("Error obtaining reference to context WebApplication");
            }

            //Verify and check if the job is already in place -> delete job
            foreach (SPJobDefinition job in webApp.JobDefinitions)
            {
                if (job.Name == JOB_NAME)
                    job.Delete();
            }

            // install the job
            MyTimerJob timerJob = new MyTimerJob(JOB_NAME, webApp) { IsDisabled = false };
            //Time
            SPFeatureDefinition timerJobFeature = GetFeatureProperties(featureGuid);

            //Obtain schedule
            SPSchedule schedule = SPSchedule.FromString(timerJobFeature.Properties[schedulePropertyName].Value);

            //Declare schedule
           timerJob.Schedule = schedule;

            timerJob.Update();
        }
        catch (Exception ex)
        {
            throw new SPException("Error occurred while installing Timer Job Definition - " + ex.Message + " - " + ex.StackTrace);
        }
    }


    private static SPFeatureDefinition GetFeatureProperties(string featureGuid)
    {
        if (featureGuid != null)
        {
            //Gets all farm features in the object
            SPFeatureDefinitionCollection farmFeatures = SPFarm.Local.FeatureDefinitions;

            //Gets specifiv feature with GUID
            SPFeatureDefinition featureDefinition = farmFeatures[new Guid(featureGuid)];

            //returns specific propertyValue
            return featureDefinition;
        }
        return null;
    }



    <?xml version="1.0" encoding="utf-8" ?>
<Feature xmlns="http://schemas.microsoft.com/sharepoint/"
         Id="6ae97a43-a342-4f66-8416-2b492c88f896"
         Title="MyTimerJob"
         Description="MyJob"
         Scope="WebApplication"
         Hidden="False"
         Version="1.0.0.0"
         ReceiverAssembly="MyTimerJob, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adc8d8d2b59e51ea"
         ReceiverClass="MyTimer.TimerJobInstaller">
  <Properties>
    <Property Key="ScheduledRunTime" Value="every 1 minutes"/>
  </Properties>
</Feature>
Was it helpful?

Solution

I solved the problem by editing the contructor code like as follows

Original line

 // install the job
        MyTimerJob timerJob = new MyTimerJob(JOB_NAME, webApp) { IsDisabled = false };

Modified line (works)

 // install the job
            MyTimerJob timerJob = new MyTimerJob(JOB_NAME, webApp);

I really don`t know what went wrong before but that does it!

OTHER TIPS

In my current project, I have been developing a bunch of functionality around project space provisioning. As part of this, I decided that as there were a lot of activities to be performed when creating and configuring the new site, developing a SharePoint Timer Job was the best option.

So lesson learnt #1 - You can't programmatically create a timer job from a site collection feature. The reason for this is that typically the application pool that looks after the site does not have permission to write to the configuration database. Creating a Timer Job requires you to be able to write the timer job definition into the configuration database, so if your application pool doesn't have the rights, then the creation of the job will fail.

So basically you have to create a Web Application level feature (i.e. activated through Application Management tab of Central Admin) with a feature receiver method that creates the timer job. E.g.

Creating the timer job in code is actually quite simple. Below is the feature activation/deactivation code:

using Microsoft.SharePoint; using Microsoft.SharePoint.Administration; using Collaboration.Projects.Provisioning; namespace Collaboration.Projects.FeatureCode { /// /// Creates the timer job that runs the site creation process for confirmed requests in the provisioning request list /// public class CollabProjectProvisioningTimerJob : SPFeatureReceiver { public override void FeatureActivated(SPFeatureReceiverProperties properties) { SPWebApplication application = properties.Feature.Parent as SPWebApplication; DeleteProvisioningJob(application); // install the job ProjectSpaceCreationTimerJob provisioningJob = new ProjectSpaceCreationTimerJob(application); SPMinuteSchedule schedule = new SPMinuteSchedule() { BeginSecond = 0, EndSecond = 59, Interval = 30 }; provisioningJob.Schedule = schedule; provisioningJob.Update(); } public override void FeatureDeactivating(SPFeatureReceiverProperties properties) { DeleteProvisioningJob(properties.Feature.Parent as SPWebApplication); } public override void FeatureInstalled(SPFeatureReceiverProperties properties) { } public override void FeatureUninstalling(SPFeatureReceiverProperties properties) { } /// /// Deletes the provisioning job if it exists /// /// private void DeleteProvisioningJob(SPWebApplication application) { foreach (SPJobDefinition job in application.JobDefinitions) { if (job.Name == ProjectSpaceConstants.ProvisioningJobName) job.Delete(); } } } }

Now the ProjectSpaceCreationTimerJob class just inherits from SPJobDefinition. Below is a code snippet (note that the Execute method is the actually code that gets executed when the job runs).

using System; using System.Net; using System.Web; using Microsoft.SharePoint; using Microsoft.SharePoint.Administration; using Collaboration.Projects.Resources; using Collaboration.Provisioning; using Collaboration.Common; using System.Text;

namespace Collaboration.Projects.Provisioning { public class ProjectSpaceCreationTimerJob : SPJobDefinition { public ProjectSpaceCreationTimerJob() : base() { } public ProjectSpaceCreationTimerJob(SPWebApplication web) : base(ProjectSpaceConstants.ProvisioningJobName, web, null, SPJobLockType.Job) { this.Title = ProjectSpaceConstants.ProvisioningJobName; }

public override void Execute(Guid targetInstanceId)
{
  // your code goes here
  base.Execute(targetInstanceId);
}

} }

Hope this helps. I've written it down here so that I remember it in the future.

Licensed under: CC-BY-SA with attribution
Not affiliated with sharepoint.stackexchange
scroll top