Thursday, 25 December 2014

Step by Step procedures to create a Timer Job in SharePoint 2013

1. Open the Visual Studio 2012.
2. Click New Project.
3. Select the Empty SharePoint Solution Template.
4. An empty project will be created as below.
clip_image002
5. Right click on the Project and Select New Folder
clip_image004
6. Name the folder as Jobs.
7. Add a class inside Jobs folder.
clip_image006
8. The class will look like this.
1
   using System;  using System.Collections.Generic;  using System.Linq;  using System.Text;  using System.Threading.Tasks;    namespace MyNamespace  {   class MyTimer   {     }  } 
9. Modify the class as shown below. i.e., we are going to inherit SPJobDefinition class and make the class as public and create the constructors as shown below.
1
using Microsoft.SharePoint.Administration;  using System;  using System.Collections.Generic;  using System.Linq;  using System.Text;  using System.Threading.Tasks;    namespace MYNamespace  {   public class MyTimer : SPJobDefinition   {   HashSet<string> seenUids = new HashSet<string>();     public MyTimer ()   : base()   {     }     public MyTimer (string jobName, SPService service, SPServer server, SPJobLockType targetType)   : base(jobName, service, server, targetType)   {     }     public MyTimer (string jobName, SPWebApplication webApplication, string strUrl)   : base(jobName, webApplication, null, SPJobLockType.ContentDatabase)   {   this.Title = jobName;   }       public override void Execute(Guid ContentDatabaseID)   {   try   {       }   catch (Exception ex)   {     }   }   }  }
10. Now the timer class is ready. Now we need to deploy this timer in to the SharePoint farm. To do this, we need to create a Feature and a FeatureReceiver. On the Activation of the Feature, we are going to add this timer into our SharePoint Farm.
11. Add a feature by right click on the Features folder.
clip_image008
12. Name the Feature and give the Description appropriately. Make the Scope of the Feature as Webapplication.
clip_image010
13. The above point is the key factor in SP2013. Because, in SP2010, we can give the scope as SiteCollection and can update the WebApplication properties from the FeatureReceiver. To do that, we have to run the power shell script to get rid of “Access Denied” Exception. To be more precise, Whenever, we are trying to update any of the WebApplication Properties, sharepoint will throw an “Access Denied” Exception. Please have a look into the below piece of code inside the FeatureActivated Event.
1
   public override void FeatureActivated(SPFeatureReceiverProperties properties)  {   try   {   SPSecurity.RunWithElevatedPrivileges(delegate()   {   SPWebApplication webapplication = properties.Feature.Parent as SPWebApplication;     if (webapplication.Properties.Contains("SiteURL"))   webapplication.Properties.Remove("SiteURL");     webapplication.Properties.Add("SiteURL", "http://MysitecollectionURL");   webapplication.Update();     foreach (SPJobDefinition job in webapplication.JobDefinitions)   {   if (job.Name == "SathishSampleTimer")   job.Delete();   }         Mytimer timer = new Mytimer("SathishSampleTimer", webapplication, "http:// MysitecollectionURL ");     SPDailySchedule schedule = new SPDailySchedule();     schedule.BeginHour = 01;   schedule.BeginMinute = 00;   schedule.BeginSecond = 00;     schedule.EndHour = 01;   schedule.EndMinute = 01;   schedule.EndSecond = 00;     timer.Schedule = schedule;   timer.Update();   });   }   catch (Exception ex)   {     }  } 
On the WebApplication.Update(), Usually we will get an “Access Denied” Exception. To overcome this, either from C# or through the PowerShell Script, we will rectify them on the SharePoint 2010. The c# or PowerShell Script is as follows.
1
   if (SPWebService.ContentService.RemoteAdministratorAccessDenied == true)  {   SPWebService.ContentService.RemoteAdministratorAccessDenied = false;   SPWebService.ContentService.Update(true);  } 
Or by using the following powershell script, we can get rid of the Access Denied Exception in SharePoint 2010.
1
   function Set-RemoteAdministratorAccessDenied-False()  {   [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") > $null   [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Administration") > $null     # get content web service   $contentService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService   # turn off remote administration security   $contentService.RemoteAdministratorAccessDenied = $false   $contentService.Update()  }    Set-RemoteAdministratorAccessDenied-False 
14. Why we are going for PowerShell is, even sometimes, SPWebService.ContentService.Update(true); will also throw access denied exception.
15. But in SP 2013, even after doing the above also, I was getting “Access Denied” exception. After spending couple of hours, identified that, the Security in SP 2013 has been increased and only, if the WebApplication Scoped Feature can make any changes on the WebApplication Level. Because, many user will be having access to different site collections. When they modify any of the Feature on any SiteCollection, it should not affect the WebApplication. For that reason, SP 2013 gives way only for the WebApplication scoped Feature to access any of the WebApplication property.
16. Hence, now we are ready to deploy our solution into the SharePoint Environment.
17. One more important thing, is for our understanding, make the default activation of the feature as false.
clip_image012
18. Even immediate below, “Always Force Install”, make it as true.
19. Make sure that on the Feature DeActivation, we are deleting the timer job. This will help us to clean the timer job, whenever the Feature gets deactivated.
1
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)  {   try   {   SPSecurity.RunWithElevatedPrivileges(delegate()   {   SPWebApplication webapplication = properties.Feature.Parent as SPWebApplication;     foreach (SPJobDefinition job in webapplication.JobDefinitions)   {   if (job.Name == "SathishSampleTimer")   job.Delete();   }   });   }   catch (Exception ex)   {     }  }
20. Now, we are ready for the deployment.
clip_image014
21. Then go to the Central Administration. Manage Web Application. Select your Web Application on which the Solution has been Deployed. Select Manage Features.
clip_image016
22. You will get the below screen.
clip_image018
23. Activate the feature.
24. On the Activation, we can see our timer job get listed on the Monitoring->Review Job Definitions.
clip_image020
25. Now, another challenging issue, regarding the debugging of Timer Job. We need to attach with the process OWSTimer.exe to debug the timer job. On the Execution, Execute will be the first method get invoked. Put a break point over there and attach to OWSTimer.exe.
26. Sometimes, we will get a strange exception like “UnAble to evaluate Expression” while debugging the timer job. This is happening because of the cross threads between the w3wp.exe and OWSTimer.exe. To overcome this, restart the IIS. This will clear the w3wp process. Then come to Services.msc and restart the SharePoint Timer Services. This will restart the OWSTimer and make sure that the latest dll is referred with the Debugger.
clip_image022
27. Whenever you make any code changes and re-deploy the solution, restart the Timer Service too. This will reduce your debugging time with strange issues. J.
28. Another Important thing to be noted as Deployment Target. Whenever you want to deploy your timer job into WebApplication scope, you will get an “Assembly cannot be loaded” loaded exception. This is because of whenever you are trying to deploy a timer, the timer will search for the DLLs from the GAC and not from the Bin of the Web Application. Hence, always, the timer job should be deployed on the GlobalAssemblyCache.
With this, the sample timer job has been created and the tips and tricks to debug and fix the errors were discussed. If you find, I missed anything or anything is wrong, please feel free to comment on that.

Start Workflow from Custom Timer Job

Start Workflow from Custom Timer Job


In this post, i will try to explain how to start a Workflow from Custom Timer Job in Sharepoint 2010. I will like to thank Mr. Andrew Connell whose blog:http://www.andrewconnell.com/Creating-Custom-SharePoint-Timer-Jobs helped me alot in the process of creating timer job. I would like to thank Mr. Ahmed Naji also. His bloghttp://dotnetfinder.wordpress.com/2010/07/24/creatingcustomsharepointtimerjob2010/ also helped me alot. It was hard for me to find working timer job that will start workflow. After a week of googling and working around, i figured out the way to do it.
Now lets start building the timer job.
First of all design the workflow in sharepoint designer and publish it to the desired list/library.
Then fire up the visual Studio.
Open Visual Studio 2010
Click on File and New then Project then Select Sharepoint 2010 on the left side and Select Empty Sharepoint Project. Name it whatever you want. In my case i had named it: Custom_TimerJobToStartWorkflow
firstStep
Deploy it as a farm Solution.
Step2
Now Create a class in the project. Right Click on the Project Name and Select Add then Click on New Item.
Name the class whatever you want. In my case i named it StartWorkflow.cs
In StartWorkflow.cs add using Microsoft.SharePoint.Administration;
In this class you will need to create a few constructors and override the Execute() method as shown below:
step3
I guess some explanations are needed over here:
Remember i asked you to design and publish the workflow first. It is beacuse, we will need the GUID of that particular workflow that we want to start. In the code you can see that we are using GUID. To get the GUID of the workflow, go back to the list where the workflow is created. In the Ribbon, Library Tools, Documents tab, click “Workflows”. In the “Start a New Workflow” section, right-click on the url that has the name of your workflow and select “Copy Shortcut”. For Example:
Look at the Url and extract the Guid from the TemplateId parameter. For example, in this url:
http://mysharepointsite/_layouts/IniWrkflIP.aspx?List={21303f3e-d36c-40f2-806e-0d2536b4ec72}&ID=4&TemplateID={aed94889-39bc-4eb9-997b-302d0f55c645}&Source=http://mysharepointsite /
The GUID that is bold above is the GUID of the workflow.
Now, this job will start the workflow everytime it is executed.
Now, next step is to add the feature.
Right Click on Features in Solution Explorer window and Click on Add Feature.
Step 5
Right Click on the “Feature1″ if you want to rename to any name. I just left it alone in my project. Click on Add Event Receiver.
Step6
Here you can see that the event Receiver class inherits from Microsoft.Sharepoint.SPFeatureReceiver and this class handles events raised during feature activation, deactivation, installation, uninstallation and upgrade. But, in our case we only need FeatureActivated and FeatureDeactivated event handler to install or uninstall our custom timer job.
Below is the code:
using System;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Administration;
namespace Custom_TimerJobToStartWorkflow.Features.Feature1
{
///
/// This class handles events raised during feature activation, deactivation, installation, uninstallation, and upgrade.
///
///
/// The GUID attached to this class may be used during packaging and should not be modified.
///
[Guid(“c33883e2-ee9a-4ec2-b042-be9d5ab1dad4″)]
public class Feature1EventReceiver : SPFeatureReceiver
{
const string List_JOB_NAME = “Start Worflow from Timer Job”;
// Uncomment the method below to handle the event raised after a feature has been activated.
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPSite site = properties.Feature.Parent as SPSite;
DeleteJob(site);
CreateJob(site);
}
private static void DeleteJob(SPSite site)
{
foreach (SPJobDefinition job in site.WebApplication.JobDefinitions)
if (job.Name == List_JOB_NAME)
job.Delete();
}
private static void CreateJob(SPSite site)
{
StartWorkflow job = new StartWorkflow(List_JOB_NAME, site.WebApplication);
SPMinuteSchedule schedule = new SPMinuteSchedule();
schedule.BeginSecond = 0;
schedule.EndSecond = 1;
schedule.Interval = 5;
job.Schedule = schedule;
job.Update();
}
// Uncomment the method below to handle the event raised before a feature is deactivated.
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
SPSite site = properties.Feature.Parent as SPSite;
foreach (SPJobDefinition job in site.WebApplication.JobDefinitions)
{
if (job.Name == List_JOB_NAME)
job.Delete();
}
}
// Uncomment the method below to handle the event raised after a feature has been installed.
//public override void FeatureInstalled(SPFeatureReceiverProperties properties)
//{
//}
// Uncomment the method below to handle the event raised before a feature is uninstalled.
//public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
//{
//}
// Uncomment the method below to handle the event raised when a feature is upgrading.
//public override void FeatureUpgrading(SPFeatureReceiverProperties properties, string upgradeActionName, System.Collections.Generic.IDictionary parameters)
//{
//}
}
}
Now, before deploying the timer job, we should select the right scope of the Feature. You can activate the Feature in Farm, Site, Web, WebApplication level. But, in our case we will activate the Feature on Site which is Site Collection. If you try to activate the feature in wrong scope you will get the error.
Step7
Now let’s deploy our custom timer job.
Right click on the project name and click Deploy. I guess, the solution should be successfully deployed if you have followed my instructions properly.
You can change the schedule of the TimerJob to run at particular time. Right now, the timer job runs every 5 minutes which will start the workflow every five minutes. So, if you want to change the timing:
Goto Central Admin, then click on Monitoring and in the Timer Jobs Sections Click on Review Job Definitions then you will see your custom timer job.
Step8
Click on it and you will see Edit Timer Job Page, where you can Modify Job Schedule based on your requirement.
Step9
Note: If you ever make changes in the code, make sure you change the Assembly Information everytime. I had some issues with this when i did not change the Assembly Infomation.
To Change the Assembly information:
Right Click on the Project Name and Click on Properties.
Then in Application Tab, you will see a Assembly Information Button.Click on that you will see Assembly version 1-0-0-0 and File version 1-0-0-0. Just increment 1 in both of those versions before deploying if you ever make any changes in the code.
Comments and Suggestions are highly appreciated.