Thursday, November 1, 2012

Service based custom timer job in SharePoint 2010

Hi Friends,

There are many articles you will find on internet about Timer Jobs in SharePoint 2010 which is based on web application but not on service. That is the reason i am sharing this article.

Timer job based on web application having one major problem. i.e- Job will not work if that application not worked or crashed or say front end on which web application hosted is down.

Here i will not tell whole story of Timer Job, you will get better information here

A Complete Guide to Writing Timer Jobs in SharePoint 2010

To create timer job based on service or say service application, we will have to do few things, this are below
  • Create custom service and add to the local farm
  • Create service instance based on above custom service and add this to all the servers in the farm
  • Create timer job
  • Associate timer job to service


Steps in detail

1: Open Visual Studio 2010 and create farm based SharePoint Solution (use blank SharePoint Project Template), add class file named CustomTimerJobService.cs, code is below


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

namespace CustomTimerJobService
{
    [System.Runtime.InteropServices.Guid("6D53ECA1-E5E4-47CF-961F-28D80C8C5B98")]
    public class CustomTimerJobService : SPService
    {
        public const string serviceName = "Custom Timer Job Service";

        //private static CustomTimerJobService local;

        public CustomTimerJobService() { }

        public CustomTimerJobService(SPFarm farm) : base("CustomTimerJobService", farm)
        { }

        //public static CustomTimerJobService Local
        //{
        //    get
        //    {
        //        if (CustomTimerJobService.local == null)
        //        {
        //            CustomTimerJobService.local = SPFarm.Local.Services.GetValue<CustomTimerJobService>("CustomTimerJobService");
        //        }

        //        return CustomTimerJobService.local;
        //    }
        //}

        public override void Provision()
        {
            base.Provision();
        }

        public override string TypeName
        {
            get
            {
                return serviceName;
            }
        }

        public override string DisplayName
        {
            get
            {
                return serviceName;
            }
        }       
    }   
}


2: Add class file named CustomTimerJobServiceInstance.cs, code is below

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

namespace CustomTimerJobService
{
    public class CustomTimerJobServiceInstance : SPServiceInstance
    {
        public const string serviceDescription = "Custom Service for service based timer jobs";

        public CustomTimerJobServiceInstance() : base()
        { }

        public CustomTimerJobServiceInstance(string name, SPServer server, CustomTimerJobService service) : base(name, server, service)
        { }

        public override string Description
        {
            get
            {
                return serviceDescription;
            }
        }
    }
}


3: Add feature of scope Farm to the solution and then add feature receiver.

Here we will add service to the local farm, then instantiate above service on all the servers in the farm.

using System;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Administration;

namespace CustomTimerJobService.Features.AddTimerJobService
{
    [Guid("8daf90a1-df8a-4646-a606-0646498a6242")]
    public class AddTimerJobServiceEventReceiver : SPFeatureReceiver
    {
        public const string serviceName = "Custom Timer Job Service";

        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            //1: Add service in local farm
            //2: Add service instance of this service on every server in the farm

            //Create service definition instance
            CustomTimerJobService timerJobService = new CustomTimerJobService(SPFarm.Local);

            //Get all services from local farm and add our custom service in farm
            SPServiceCollection services = SPFarm.Local.Services;
            services.Add(timerJobService);
            SPFarm.Local.Update();

            //Get all servers in local farm
            SPServerCollection servers = SPFarm.Local.Servers;

            //Add service instance on all the servers
            foreach (SPServer server in servers)
            {
                //Create new service instance based on our custom service and add in server
                CustomTimerJobServiceInstance timerJobServiceInstance = new CustomTimerJobServiceInstance(serviceName, server, timerJobService);
                server.ServiceInstances.Add(timerJobServiceInstance);
                server.Update();
            }
        }

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            //1: Remove service instance of this service on every server in the farm
            //2: Remove service in local farm

            //Get all servers in local farm
            SPServerCollection servers = SPFarm.Local.Servers;

            foreach (SPServer server in servers)
            {
                //Remove instance on every server
                CustomTimerJobServiceInstance timerJobServiceInstance = server.ServiceInstances.GetValue<CustomTimerJobServiceInstance>();
                    
                if (timerJobServiceInstance != null && timerJobServiceInstance.DisplayName.ToString().Equals(serviceName, StringComparison.OrdinalIgnoreCase))
                {
                    server.ServiceInstances.Remove(timerJobServiceInstance.Id);
                    server.Update();                       
                }
            }

            //Remove service from the farm
            CustomTimerJobService timerJobService = SPFarm.Local.Services.GetValue<CustomTimerJobService>();

            if (timerJobService != null)
            {
                timerJobService.Delete();
                SPFarm.Local.Update();                   
            }           
        }
    }
}


Next step is to create timer job and associate it to service


Steps in detail

1: Open Visual Studio 2010 and create farm based SharePoint Solution (use blank SharePoint Project Template), add class file named CustomTimerJob.cs.cs, code is below


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

namespace CustomTimerJobDemo
{
    public class CustomTimerJob : SPFirstAvailableServiceJobDefinition
    {
        //If you are taking configuration values from the site where you are going
        //to activate this timer job feature then make persisted property
        //By doing this we can use it further
        [Persisted]
        public string configSiteURL = null;

        public CustomTimerJob()
            : base()
        { }

        public CustomTimerJob(string jobName, SPService service, SPSite site)
            : base(jobName, service)
        {
            this.Title = jobName;
            this.configSiteURL = site.Url;
        }


        public override void Execute(SPJobState jobState)
        {
            if (jobState.ShouldStop != true)
            {
                this.UpdateProgress(10);

                //To Do: Do some activity here

                this.UpdateProgress(100);
            }
        }
    }
}


2: Add feature of scope Site to the solution and then add feature receiver.

Here we will associate timer job to service


using System;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Deployment;

namespace CustomTimerJobDemo.Features.CustomTimerJobDemo
{
    [Guid("a26f0c48-6464-4438-bbd0-35fac5218a0b")]
    public class CustomTimerJobDemoEventReceiver : SPFeatureReceiver
    {
        public const string jobName = "Custom Timer Job for demo";

        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            SPSite currentSite = properties.Feature.Parent as SPSite;

            //Check current context whether it is a normal feature activation or through any custom deployment job
            //Timer job should not be created if feature activation occurs through any custom deployment job
            if (!SPImportContext.Current.IsRunning)
            {
                SPService timerJobService = GetCustomTimerJobService();

                if (timerJobService != null)
                {
                    // Remove job if it already associated with the service
                    foreach (SPJobDefinition job in timerJobService.JobDefinitions)
                    {
                        if (job.Name.Equals(jobName, StringComparison.OrdinalIgnoreCase))
                        {
                            //Deleting existing job
                            job.Delete();
                        }
                    }

                    //Create new job here
                    CustomTimerJob timerJob = new CustomTimerJob(jobName, timerJobService, currentSite);

                    SPDailySchedule dailySchedule = new SPDailySchedule();
                    dailySchedule.BeginMinute = 0;
                    dailySchedule.EndMinute = 59;
                    dailySchedule.BeginHour = 0;
                    dailySchedule.EndHour = 12;

                    timerJob.Schedule = dailySchedule;
                    timerJob.Update();
                }
            }                                     
        }

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            //Get custom timer service
            SPService timerJobService = GetCustomTimerJobService();

            if (timerJobService != null)
            {
                // Remove job
                foreach (SPJobDefinition job in timerJobService.JobDefinitions)
                {
                    if (job.Name.Equals(jobName, StringComparison.OrdinalIgnoreCase))
                    {
                        //Deleting job
                        job.Delete();
                    }
                }
            }
           
        }

        private static SPService GetCustomTimerJobService()
        {
            SPService timerJobService = null;           
            string serviceName = "Custom Timer Job Service";
                           
            //Get all services from the farm
            SPServiceCollection services = SPFarm.Local.Services;

            foreach (SPService service in services)
            {
                if (service.DisplayName.Equals(serviceName, StringComparison.OrdinalIgnoreCase))
                {
                    timerJobService = service;
                    break;
                }
            }

            if (timerJobService == null)
            {
                throw new Exception("Service not available. Please check service on servers.");
            }           
           
            return timerJobService;
        }
    }
}


This is done now, you can go to central admin and run timer job or it will run based on schedule you configured for it.

Bye Good Day....!


Wednesday, September 26, 2012

Threading example in C#

using System;
using System.Text;
using System.Threading;
using System.Collections;
using System.Collections.Generic;

namespace Threading_Demo
{
    public class Threading
    {
        ArrayList data = null;

        ManualResetEvent[] totalEvents = null;
        
        public Threading(ArrayList data)
        {
            this.data = data;
            this.totalEvents = new ManualResetEvent[data.Capacity];
        }

        public void ProcessThreads()
        {
            WaitCallback callBack = new WaitCallback(ProcessData);

            int resetIndex = 0;

            foreach (object item in data)
            {
                //Create thread and add it in pool
                ThreadPool.QueueUserWorkItem(callBack, resetIndex + "#" + item);

                //Create new event
                totalEvents[resetIndex++] = new ManualResetEvent(false);
            }

            if (totalEvents != null)
            {
                WaitHandle.WaitAll(totalEvents);
            }
        }

        private void ProcessData(object state)
        {
            string objState = state as string;
            string[] stateParam = objState.Split('#');

            if (stateParam.Length == 2)
            {
                int threadId = Convert.ToInt32(stateParam[0]);

                if (!string.IsNullOrEmpty(stateParam[1]))
                {
                    string data = stateParam[1];

                    //Process data
                    Console.Write("Thread Id: " + threadId.ToString() + " Data: " + data.ToString() + "\n");

                    //Signal to pool after current thread finished it's porceesing
                    totalEvents[threadId].Set();
                }
            }
        }        
    }

    class Program
    {
        static void Main(string[] args)
        {
            ArrayList data = new ArrayList(5) { "One", "Two", "Three", "Four", "Five"};

            Threading thread = new Threading(data);
            thread.ProcessThreads();

        }
    }
}

Tuesday, July 17, 2012

SharePoint Server 2013 released in preview along with Pro and Developer training materials

Today is good news for SharePoint professionals, finaly Microsoft released SharePoint new version that is SharePoint Server 2013 in preview edition, though it's preview we get chance to look into it and play with new features

Here below are few usefull links

SharePoint 2013 new features and capabilities

SharePoint 2013 training for developers

What's new for developers in SharePoint 2013

Download Microsoft SharePoint Server 2013 Preview

Tuesday, January 10, 2012

Find all ContentByQueryWebParts from the page programatically

Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager manager = web.GetLimitedWebPartManager("Pages/default.aspx", PersonalizationScope.Shared);

foreach (Microsoft.SharePoint.WebPartPages.WebPart webPart in manager.WebParts)
{
 string type name="Microsoft.SharePoint.Publishing.WebControls.ContentByQueryWebPart, Microsoft.SharePoint.Publishing, Version=14.0.0.0,   Culture=neutral,    PublicKeyToken=71e9bce111e9429c";

 Type type = webPart.GetType();
 if (type.FullName.Contains("ContentByQueryWebPart")
 {
  //then it is ContentByQueryWebPart
 }
}

Friday, August 19, 2011

Unable to open SharePoint site on host machine

Few weeks back, i created one SharePoint site means a web application using Central Admin. One thing which i did different from usual is Host hearder entry. After creating site i tried to open it using host header or say fully qualified name but i couldn't open it on my local machine but though i can open it from other machines.

Also one more problem i was facing at the time of creating new SharPoint project from Visual Studio 2010. Error like below
Cannot connect to SharePoint Site: http://<sitename>/. Make sure that this valid URL and the SharePoint site is running on the local computer. If you moved this project to a new computer or if the URL of the SharePoint site has changed since you created the project, update the Site URL Property of the project.

One of my friend gave me this useful link that i am sharing with you

http://support.microsoft.com/kb/896861

To create/open project in Visual Studio try to use host header URL not machine name or localhost.

Thursday, May 5, 2011

Sharepoint: User Type field in schema.xml

I was writting schema.xml for Custom List Template, there i need field of type User like below


I was setting value of ShowField property to Job Title which i was using in CAML query to filter out the users. I searched lot for ShowField values of User type but i coudn't found anything from MSDN, even not an expected results from google. I am very much habitual of seeing the View Source of the HTML pages so i see the page source of Task list's User column and i got all the values from that source. I think looking out HTML pages source is not a bad practice :)

Friday, April 22, 2011

Webpart Preview Page: Event handler not firing in webpart

Today i faced realy strange issue with button event handler in webpart, my webpart created from SharePoint webpart class. This is code

public class MyFirstWebPart : Microsoft.SharePoint.WebPartPages.WebPart
{
 Label userName = new Label();
 Button button;

 protected override void CreateChildControls()
 {
  button = new Button();
  userName.Text = "Sandip";
  button.Text = "Change this text";
  button.Click+=new EventHandler(button _Click);
  this.Controls.Add(userName);
  this.Controls.Add(button);
 }

 protected void button _Click(object sender, EventArgs e)
 {
  userName.Text = "Sandip Patil";
 }
}

I wired up event handler in CreateChildControls method so that was not an issue. Issue is with testing webpart on the page. I was testing webpart on webpart preview page. You can find webpart preview page whenever you select any webpart from webpart gallery page. After 1 hour of wasting time, i created one webpart page and put that webpart inside webpart zone. Thereafter i could see that event handler was firing. Means problem was not with the code but with testing scenario.
Be careful when you test webpart on Webpart Preview page.
Good Bye, Have a nice time...!