1

Here's my FeatureActivated method:

public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
    SPSite site;
    MyCustomJob customJob;      
    SPDailySchedule schedule;

    site = properties.Feature.Parent as SPSite;
    customJob = new MyCustomJob(site.WebApplication, site);

    schedule = new SPDailySchedule();
    schedule.BeginHour = 1;
    schedule.BeginMinute = 0;
    schedule.EndHour = 1;
    schedule.EndMinute = 59;

    customJob.Schedule = schedule;
    customJob.Update();
}

And here is the MyCustomJob class:

public class MyCustomJob : SPJobDefinition
{
    private SPSite site;

    public MyCustomJob() 
        : base()
    {
    }

    public MyCustomJob(string jobTitle, SPService service, SPServer server, SPJobLockType lockType)
        : base(jobTitle, service, server, lockType)
    {
        this.Title = jobTitle;
    }

    public MyCustomJob(string jobTitle, SPWebApplication webApplication)
        : base(jobTitle, webApplication, null, SPJobLockType.None)
    {
        this.Title = jobTitle;
    }

    public MyCustomJob(SPWebApplication webApplication, SPSite site)
        : base("MyCustomJob", webApplication, null, SPJobLockType.None)
    {
        this.Title = "My Custom Job";
        this.site = site;
    }

    public override void Execute(Guid targetInstanceId)
    {
        SPSite mySite;

        // This is always null!!!
        mySite = this.site;
    }
}

When I debug the solution, I see that every time the timer job needs to be instantiated, it is done using the default constructor. If that is the case, it's no wonder this.site is always null.

So the question is: Why is the last constructor never called and how can I have the SPSite object available in the timer job?

3

You could try stroring the site url in timerjob properties collection and retrieve it in the Execute method of timerjob

In the feature activated event store the siteUrl

string key = "mySiteUrl";
string value = web.Url;

TimerJob tmrJob = new TimerJob(webApp);
//remove the key if already exists
bool isKeyExists = tmrJob.Properties.ContainsKey(key);
if (isKeyExists)
{
    tmrJob.Properties.Remove(key);
}
tmrJob.Properties.Add(key, value);

Retrieve the info in Execute method:

public override void Execute(Guid targetInstanceId)
{
    if (!string.IsNullOrEmpty(this.Properties["mySiteUrl"].ToString()))
    {
        mySiteUrl = this.Properties["mySiteUrl"].ToString();
    }

    if (!string.IsNullOrEmpty(mySiteUrl))
    {
        using (SPSite mySite = new SPSite(mySiteUrl))
        {
            using (mySiteWeb = mySite.OpenWeb())
            {
                //provide your logic here for the site
            }
        }
    }
}

http://adicodes.com/timer-job-in-sharepoint-for-specific-site/

  • This will probably work, let me try it out, and I'll mark your reply as Accepted if it does. Any idea why the default constructor is called instead of the one I call in the feature activated? – Boris Oct 3 '13 at 10:13
  • I think it is a standard behavior, when you run the timer job from CA, at that time timer job doesn't know that you want to call the constructor with webapplication and site parameters. – Nadeem Yousuf Oct 3 '13 at 11:13
  • You've created the job definition with the non-default constructor, which saves the job to the database. Every time the schedule comes up it deserializes the saved job using the default constructor, and the site field isn't being persisted. – lgaud Oct 3 '13 at 14:42
0

make sure the flow of information! is correct when the timer job is executed what method is called first and is the spsite set then?

ask yourself is MyCustomJob method being hit? can you debug:

public MyCustomJob(SPWebApplication webApplication, SPSite site)
    : base("MyCustomJob", webApplication, null, SPJobLockType.None)
{
    this.Title = "My Custom Job";
    this.site = site;
}

is site varible not null and is it setting the global varible?

how about instead of using the local site varible and use instead the webapplication to get the spsite!

this.site = webApplication.sites[MySiteName];

the above code should work with no issues! just incase the spsite is different to the one you passed making it null!

or how about using the current spwebapplication to get the webapp or spsite?

SPWebApplication webApp = this.Parent as SPWebApplication;

or

SPSite site = this.Parent as SPSite;

so it would look like this:

public override void Execute(Guid targetInstanceId)
{
    SPWebApplication webApp = this.Parent as SPWebApplication;
    SPSite mySite = webApplication.sites[MySiteName];
    //do what you want with mysite
}

or

public override void Execute(Guid targetInstanceId)
{
    SPSite mySite = this.Parent as SPSite;

    //do what you want with mysite
}

http://msdn.microsoft.com/en-us/library/ff798313.aspx

EDIT

just to make it clear your execute code CAN NOT get spsite or web and needs to get it from spfarm or webapp! either way above should work! the timer job is running under a different context and i belive looses the spsite!

  • Thanks for the reply. The flow of information is pretty much default for a timer job. Feature gets activated - the timer job gets registered; I can't debug that part of course. Next, I run the timer from Central Admin and then the breakpoint set on the default constructor fires. Next, the Execute method happens. The reason why the this.site is null is because the wrong constructor is called. But why? And one more thing: Dude, what's with the exclamation marks? – Boris Oct 3 '13 at 10:11
  • lol cant help it ;) , have you tried the method at the bottom of my post to get the spsite? via webapp or parent spsite – Ali Jafer Oct 3 '13 at 10:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.