Friday, May 6, 2011

Creating Custom SharePoint Timer Job

When I started looking for some materials on SharePoint Timer Job, I was overwhelmed to see the contents available, however I felt to share my part of SharePoint Timer Job experience. This being my first effort to create the timer job, I was bit confused with the windows scheduler. Though, the SharePoint timer job is very simple and straight forward.

Let me give the topic a totality by outlining the points I would wish to cover

1.    When do we need to create a custom SharePoint timer job?

2.    How to create it?

3.    How to deploy it in Development Environment?

4.    How to debug it?

5.    How to deploy it in Test/Production Environment?

6.    Errors you might face

 

1.    When do we need to create a custom SharePoint timer job?

When we want SharePoint to act on a scheduled time without any user intervention, such as sending mails, fetch external data, synchronizing lists etc. on a periodical basis.

2.    How to create it?

The timer job would need only two classes (i) The timer job and (ii) Feature Receiver class

a)    Need to create a class that will inherit from the SPJobdefintion class, i.e. from "Microsoft.SharePoint.Administration.SPJobdefinition".  Add the reference of the namespace using Microsoft.SharePoint.Administration; the class would look like public class MySPTimerJobActivation : SPJobDefinition

b)    Constructor is very important in SP Timer Jobs. In this code the constructor would be called from the feature receiver class while instantiating the MySPTimerJobActivation. There are two overloaded constructors apart from the default contractor available, in my case the one I have used is sufficient.

#region Overloaded Contructors

public MySPTimerJobActivation(): base()

{

}

public MySPTimerJobActivation(string jobName, SPWebApplication webApp, SPServer server, SPJobLockType joblock)

            : base(jobName, webApp, server, joblock)

{

   this.Title = jobName;

}

#endregion

 

c)     Implement the desired code in Execute() method. Whenever the timer job would be activated, this Execute() method would be called. Another important thing worth mentioning is from within the Timer Jobs class we will not be able to get the reference to the site, since the context is different. Thus we need to put the site url in the properties bag of the timer job class while activating the feature in feature receiver class and use it here

public override void Execute(Guid targetInstanceId)

{

string strUrl = this.Properties["SiteURL"].ToString();

SPSite oSiteColl = new SPSite(strUrl)

////Desired Code to execute here

 

}

The Timer Job Class would look something like this.

public class MySPTimerJobActivation : SPJobDefinition

{

  #region Overloaded Contructors

  public MySPTimerJobActivation()

  : base()

  {

  }

 

  public MySPTimerJobActivation(string jobName, SPWebApplication webApp, SPServer server, SPJobLockType joblock)

  : base(jobName, webApp, server, joblock)

  {

    this.Title = jobName;

  }

  #endregion

 

  #region Execute Method

  public override void Execute(Guid targetInstanceId)

  {

    string strUrl = this.Properties["SiteURL"].ToString();

    string strListName = "TimerList";

    try

    {

      using (SPSite oSiteColl = new SPSite(strUrl))

      {

        using (SPWeb oWeb = oSiteColl.OpenWeb())

          {

            ////Desired Code to execute here

            ////Get the list item

       SPListItemCollection oItemColl = oWeb.Lists[strListName].Items;

            ////Add new item

            SPListItem oListItem = oItemColl.Add();

            ////Logging the data

            oListItem["Title"] = "From MySP Timer Job";

            oListItem["DateTimeFired"] = DateTime.Now;

            oListItem.Update();

          }

        }

      }

      catch (Exception ex)

      {

        PortalLog.LogString("Exception occured in Notification Update Module – {0} – {1}", ex.Message, ex.StackTrace);

      }

    }

   #endregion

}

The timer job class is complete now. The feature receiver class would be the next stop to look into

d)    The Feature Receiver Class would be similar to any other receiver class inheriting from SPFeatureReceiver. There are few very important and interesting things to remember at this point.

i)              Pass the parameter in Constructor – “SPServer” as null (the constructor would expect this parameter)

ii)             SPJobLockType.Job – Options are ContentDatabase,Job,None

Consider the different available Job Locks:

·         SPJobLockType.ContentDatabase - Locks the content database. A timer job runs one time for each content database that is associated with the Web Application; therefore your job will run as many times for each content database associated with the Web Application that exists

·         SPJobLockType.Job - Locks the timer job. This prevents multiple instances of the job from running on a single server (Recommended).

·         SPJobLockType.None - No locks

 

iii)            oTimerJob.Properties["SiteURL"]=SiteCol.Url; as mentioned earlier we would need this site url in the Execute Method of Timer Job class

iv)            Good practice to delete any previous instance of the job

////Deleting the Job on deactivation of the feature

    foreach (SPJobDefinition objMyJob in jobCol)

    {

      if (objMyJob.Name == My_Timer_Job)

      jobToDelete = objMyJob;

    }

    if (jobToDelete != null)

    jobToDelete.Delete();

 

Do not delete the job within the enumeration rather get the job and delete it outside the enumeration.

v)             Timer Job Running Intervals



If you want to run it at 11:05 PM every day, use SPDailySchedule class to configure:

SPDailySchedule tempSchedule = new SPDailySchedule();

tempSchedule.BeginHour = 23;

tempSchedule.BeginMinute=5;

tempSchedule.BeginSecond = 0;

tempSchedule.EndSecond = 15;

tempSchedule.EndMinute = 5;

tempSchedule.EndHour = 23;

oTimerJob.Schedule = tempSchedule;                oTimerJob.Update();

If you want to run it on the 1st of every month between 1:15am to 1:30am, use SPMonthlySchedule

SPMonthlySchedule schedule = new SPMonthlySchedule();  


schedule.BeginDay = 1;  


schedule.EndDay = 1;  


schedule.BeginHour = 1;  


schedule.EndHour = 1;  


schedule.BeginMinute = 15;  


schedule.EndMinute = 30; 


tempJob.Schedule = schedule;


tempJob.Update();


 


If you want to run on Monday every week between 2:01:00 am to 2:01:05 am, use SPWeeklySchedule 


 


SPWeeklySchedule schedule = new SPWeeklySchedule();


schedule.BeginDayOfWeek = DayOfWeek.Monday;


schedule.BeginHour = 2;


schedule.BeginMinute = 1;


schedule.BeginSecond = 0;


schedule.EndSecond = 5;


schedule.EndMinute = 1;


schedule.EndHour = 2;


schedule.EndDayOfWeek = DayOfWeek.Monday;


tempJob.Schedule = schedule;


tempJob.Update();


If every year on Jan 23 at 9:05AM, use SPYearlySchedule



SPYearlySchedule JobSchedule = new SPYearlySchedule();


JobSchedule.BeginMonth = 1;


JobSchedule.EndMonth = 1;


JobSchedule.BeginDay = 23;


JobSchedule.EndDay = 23;


JobSchedule.BeginHour = 9;


JobSchedule.EndHour = 9;


JobSchedule.BeginMinute = 5;


JobSchedule.EndMinute = 5;


JobSchedule.BeginSecond = 0;


JobSchedule.EndSecond = 5;


tempJob.Schedule = schedule;


tempJob.Update();



 



At the end the class would look like below. As said earlier this class will inherit from the Microsoft.SharePoint.SPFeatureReceiver class and implement the FeatureActivated & FeatureDeactivated event handlers:








public class MySPTimerJobActivationFeatureReceiver : SPFeatureReceiver



{



public const string My_Timer_Job = "Notification Timer Job";



#region Feature Activated



public override void FeatureActivated(SPFeatureReceiverProperties properties)



{



 try



  {



    ////Get the Site collection



    SPSite SiteCol = (SPSite)properties.Feature.Parent;



    SPWebApplication webApp = SiteCol.WebApplication;



    SPJobDefinitionCollection jobCol = webApp.JobDefinitions;



    ////Deleting older vrsion of Job if exists               



    SPJobDefinition jobToDelete = null;



    ////Deleting the Job on deactivation of the feature



    foreach (SPJobDefinition objMyJob in jobCol)



    {



      if (objMyJob.Name == My_Timer_Job)



      jobToDelete = objMyJob;



    }



    if (jobToDelete != null)



    jobToDelete.Delete();



  ////Install the Job Definition



  MySPTimerJobActivation oTimerJob = new      MySPTimerJobActivation(My_Timer_Job, webApp, null, SPJobLockType..Job);



 ////Set the Site Url.. will be used later from the Timer Job Class



  oTimerJob.Properties["SiteURL"] = SiteCol.Url;



  ////Run the Scheduler every 2 minutes



  SPMinuteSchedule minSchedule = new SPMinuteSchedule();



  minSchedule.BeginSecond = 0;



  minSchedule.EndSecond = 30;



  minSchedule.Interval = 2;



  oTimerJob.Schedule = minSchedule;



  oTimerJob.Update();



  }



  catch (Exception ex)



  {



  Microsoft.Office.Server.Diagnostics.PortalLog.LogString("Exception  occured in fetch query module– {0} – {1}", ex.Message, ex.StackTrace);



  }



}



#endregion



 



#region Feature Deactivating



public override void FeatureDeactivating(SPFeatureReceiverProperties properties)



{



            try



            {



                SPSite SiteCol = (SPSite)properties.Feature.Parent;



                SPWebApplication webApp = SiteCol.WebApplication;



                SPJobDefinitionCollection jobCol = webApp.JobDefinitions;



                ////Deleting older vrsion of Job if exists               



                SPJobDefinition jobToDelete = null;



                ////Deleting the Job on deactivation of the feature



                foreach (SPJobDefinition objMyJob in jobCol)



                {



                    if (objMyJob.Name == My_Timer_Job)



                        jobToDelete = objMyJob;



                }



                if (jobToDelete != null)



                    jobToDelete.Delete();



            }



            catch (Exception ex)



            {



                Microsoft.Office.Server.Diagnostics.PortalLog.LogString("Exception occured in fetch query module– {0} – {1}", ex.Message, ex.StackTrace);



            }



}



#endregion




 



3.    How to deploy in Dev Environment?



Now... to get it working, all you need to do is:



     I.        Deploy the strongly named assembly to the GAC.



    II.        Reset IIS (required for SharePoint to "see" the new timer job in the GAC) or AppPool



   III.        Create a feature specifying the receiver class and assembly that contains the event receivers.



   IV.        Install the feature.



    V.        Activate the feature.



If the WSPBuilder is installed, these all task could be performed from Visual Studio à WSPBuilder deploy option will do everything except the Activate feature.



Now the Timer Job is ready and we have to install it on the farm and deploy to our web application. The "recommended way" for doing this would be to create a Feature Receiver and implement the FeatureActivated event. In this event, can instantiate the job, set the job schedule and update the Job. Below is the code snippet of the Feature.xml



 








<?xml version="1.0" encoding="utf-8"?>



<Feature  Id="E4922BE5-5F1E-448b-9BD9-4CA4B1C652CD"



          Title="MySPTimerJob"



          Description="This feature will create a MySp Timer Job"



          Version="1.0.0.0"



          Hidden="FALSE"



          Scope="Site"



          ImageUrl ="DECISION.GIF"



          DefaultResourceFile="core"



          ReceiverAssembly="MySPTimerJob, Version=1.0.0.0, Culture=neutral, PublicKeyToken=86244771e654f5a1"



         ReceiverClass="MySPTimerJob.MySPTimerJobActivationFeatureReceiver"



          xmlns="http://schemas.microsoft.com/sharepoint/">



</Feature>




 



The Feature Receiver Class has already been discussed earlier with few examples on schedule timer to run hourly, daily, yearly, monthly, weekly or minute basis.



Depending on the requirement, sometimes the feature could be deployed at WebApplication level keeping scope as webapplication i.e, Scope="WebApplication" then we can activate the feature from Central Admin as well.



Activating this feature will deploy this Timer Job on the web application. Once the solution is deployed, can either activate the feature using stsadm -o activatefeature command or go to Central Administration -> Application Management -> Manage Web Application Features -> select web application -> Activate your Feature as shown in the snapshot below







 



Once the feature is activated, it should show up on the Timer Job Definitions page in Central Administration / Operations. It won't appear in the Timer Job Status page until it's executed at least one time.



OK L, I know it is giving a typical WSS_Config database error once trying to activate the feature or it is not showing in the Timer Job Definitions. There is nothing wrong with the code rather it is about the permission. The feature needs firm admin credential to activate it. See below section on Error you might face - for solution or visit by blog on “The EXECUTE permission was denied on the object 'proc_putObject', database 'SharePoint_Config'”. Testing the timer job in dev environment, we can temporarily change the application pool account to the application pool account being used for Central Administration. Once that is done, try activating.



4.    How to debug it?



Debugging a timer job application is not simple as compared to some other custom developed components of SharePoint. The SharePoint Timer jobs runs with the SharePoint Firm Admin credentials since, the information get into the SharePoint Config Database. Thus the application pool will not have the access. I guess, is that the timer service is supposed to run under NT AUTHORITY\NetworkService windows account which has SHAREPOINT\System SharePoint privileges, and thus there's no need to elevate privileges for a timer job.



SharePoint Jobs do not have a current context, they are executed by another windows process called “Windows SharePoint Services Timer”. The executable name of this process is “OWSTIMER.EXE”. This is the process that should be attached to the code within Execute() method to be able to debug the job



 



Set Breakpoints in your code especially the Execute() method. Click on "Attach to Process..." from the menu bar as shown below:





 



Check the box at the bottom "Show Processes from All Users".

Select OWSTIMER.EXE



 





Click the Attach button and a breakpoint should display.



 



 



5.    How to deploy it in Test/Production Environment?



Create the solution package of the timer job and deploy in production environment by automated stsadm.exe scripts.



ScriptDeployTimerJob.bat



@echo Off



echo **************************** Deployment Starts ******************************



@Set STSADM="C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN\stsadm.exe"



echo -----------------------------------------------------------------------------



%STSADM% -o addsolution -filename MySPTimerJobr.wsp



echo -----------------------------------------------------------------------------



%STSADM% -o deploysolution -name MySPTimerJobr.wsp -allowgacdeployment -immediate



Rem %STSADM% -o execadmsvcjobs



echo -----------------------------------------------------------------------------



echo **************************** Deployment ends ******************************



 



6.    Errors you might face












1



The EXECUTE permission was denied on the object 'proc_putObject', database 'SharePoint_Config', schema 'dbo'.



The SharePoint Timer jobs runs with the SharePoint Firm Admin credentials since, the information get into the SharePoint Config Database. Thus the application pool will not have the access.



1. Can run the stsadm with firm admin credential and activate the feature.



2. You can create a hidden feature and activate it, making sure you are logged in as a farm administrator




 



Please post a comment if you have other ways of doing this same thing… I’ll be happy to hear.







If this helps...... then please share......



HaPpY CoDiNg... (Aurum)



 

Thursday, May 5, 2011

How to add CSS and JavaScript in SharePoint Web Parts

While creating a web part I had to use some JavaScript and CSS. There are definitely other ways of doing this, I am just sharing the way I did it.

As you all know CSS is used for the look and feel. I had kept the CSS and JS files under the 12 hive folder structure. See below the folder structure of my solution.
image

In this example the name of the CSS file is Style.css, while deploying this, the files would be deployed inside 12 hive àLayouts folder. The basic objective is to refer this CSS file from inside the web part .cs file and render the look and feel. I have used HtmlLink to achieve this, first need to provide the path of the css file and then add to the page header controls collection section, find below the code

////--CSS file for the webpart--------------------

HtmlLink link = new HtmlLink();
link.Href = "/_layouts/A/CSS/Style.css";
link.Attributes.Add("type", "text/css");
link.Attributes.Add("rel", "stylesheet");
this.Page.Header.Controls.Add(link);

JavaScript file would also reside in the same folder structure in 12 hive, however while adding it in the code, used the Client script Manager

////-- Adding JavaScript file ----------

ClientScriptManager cs = Page.ClientScript;

if (!cs.IsClientScriptIncludeRegistered("tab_javascript"))
{
     cs.RegisterClientScriptInclude(this.GetType(), "tab_javascript", "/_layouts/A/Scripts/Script.js");
}

Please post a comment if you have other ways of doing this same thing… I'll be happy to hear.

HaPpY CoDiNg... (Aurum)

Sunday, April 17, 2011

Deploying Item Event Receiver (SPItemEventReceiver) in two approaches Feature Receiver and only feature (thru elements.xml)

While creating Event handlers/receivers, we have the option of creating the same in two different approaches. We can create event handlers to be associated with one particular list or all lists available with the same template type. Thus there could be two ways of implementing the receivers, though it all depends on the requirements.

In recent time I have created Item Event Receivers in both the ways, analyzed and have some findings to share, not sure whether this helps others. To see how to create Item Event Receivers visit my blog on How to create Item Event Receiver (SPItemEventReceiver)
Process 1(Generic with no Feature receivers)

We can find the template type in Elements.xml. See below the Receiver will get associated with all lists which has TemplateID as 100.

<?xml version="1.0" encoding="utf-8" ?>

<Elements xmlns=http://schemas.microsoft.com/sharepoint/>

<Receivers ListTemplateId="100">

In this process we only need the below files

  1. Feature.xml
  2. Elements.xml
  3. Event Handler class (event handler class inhering from SPItemEventReceiver)

 

  1. Feature.xml

The feature file will remain very simple, only with the basic details.

<?xml version="1.0" encoding="utf-8"?>

<Feature Id="62B66824-3AE2-4320-9949-6B59ED862C64"
Title="TestEventHandler"

Description="Adding/updating/deleting of any item in list"

Version="1.0.0.0"

Hidden="FALSE"

Scope="Web"

DefaultResourceFile="core"

ImageUrl ="NEWSPG.GIF"

xmlns="http://schemas.microsoft.com/sharepoint/">

<ElementManifests>

<ElementManifest Location="elements.xml"/>

</ElementManifests>

</Feature>
The feature will be very simple and straight forward, nothing special about this except mentioning the element manifest.

  1. Elements.xml

The elements.xml will hold all the receiver information.

<?xml version="1.0" encoding="utf-8" ?>

<Elements xmlns=http://schemas.microsoft.com/sharepoint/>

<Receivers ListTemplateId="100">

<Receiver> <Name>AddingEventHandler</Name>

<Type>ItemAdded</Type>

<SequenceNumber>10000</SequenceNumber>

<Assembly>TestEventHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ab011vdd6a7bfaba2</Assembly>
<Class>TestEventHandler.TestEventHandler</Class>
<Data></Data>
<Filter></Filter>
</Receiver>
<Receiver>
<Name>UpdatedEventHandler</Name>

<Type>ItemUpdated</Type>

<SequenceNumber>10000</SequenceNumber>

<Assembly>TestEventHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ab011vdd6a7bfaba2</Assembly>
<Class>TestEventHandler.TestEventHandler</Class>
<Data></Data>
<Filter></Filter>
</Receiver>
<Receiver>
<Name> Delete</Name>
<Type>ItemDeleting</Type>
<SequenceNumber>10000</SequenceNumber>
<Assembly>TestEventHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ab011vdd6a7bfaba2</Assembly>
<Class>TestEventHandler.TestEventHandler</Class>
<Data></Data>
<Filter></Filter>
</Receiver>
</Receivers>
</Elements>
Here on any item added/updated and deleting the event will fire and the class <Class>TestEventHandler.TestEventHandler</Class> would handle the events.

  1. Event Handler Class

Event handler class would inherit the base class and contain the custom code under.....

public class TestEventHandler: SPItemEventReceiver

public override void ItemAdded(SPItemEventProperties properties)

public override void ItemUpdated(SPItemEventProperties properties)

Process 2 (Feature receivers with target list)

If any Receiver is targeted for any particular list then it is always advisable to deploy the solution explicitly with the feature receiver and add to the Specific List's receiver collection. This will have two major advantages.

  1. The event handler will only get attached to the particular list on feature activation and would be removed on feature deactivation. (as compared to Process 1 approach, on feature deactivation the event receiver will still remain associated with the list)
  2. We can target the specific list to associate the

In this process we only need the below files

  1. Feature.xml
  2. FeatureReceiver
  3. Event Handler class (event handler class inhering from SPItemEventReceiver)

 

  1. Feature.xml

<?xml version="1.0" encoding="utf-8"?>

<Feature Id="62B66824-3AE2-4320-9949-6B59ED862C64"
Title="TestEventHandler"
Description="Adding/updating/deleting of any item in list"
Version="1.0.0.0"
Hidden="FALSE"
Scope="Web"
DefaultResourceFile="core"
ImageUrl ="NEWSPG.GIF"

ReceiverAssembly="TestEventHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ab011vdd6a7bfaba2"
ReceiverClass = "TestEventHandler.TestEventHandler"
xmlns=http://schemas.microsoft.com/sharepoint/>
</Feature>

Adding the Assembly and the feature receiver class information.

  1. Feature Receiver Class

This class would add the event handler class TestEventHandler to the Receiver
collection.

public class TestFeatureReceiver : SPFeatureReceiver

public override void FeatureActivated(SPFeatureReceiverProperties properties)

{
////This will the receiver collection of the list

using (SPWeb oWeb = (SPWeb)properties.Feature.Parent)

{
SPList oList = oWeb.Lists[strListName];

SPEventReceiverDefinitionCollection oEventDefColl = oList.EventReceivers;

////Set the values for the Definition object

string strAssemblyName = "TestEventHandler,Version=1.0.0.0, Culture=neutral, PublicKeyToken=ab011vdd6a7bfaba2";

string strClassName = "TestEventHandler.TestEventHandler2;

string strReceiverName = "TestListEventHandler";

string strDefData = "Data";

int intSequenceNo = 2001

////Create the Definition object

SPEventReceiverDefinition oEventDef = oEventDefColl.Add();

oWeb.AllowUnsafeUpdates = true;
////Set the properties

oEventDef.Name = strReceiverName;
oEventDef.Assembly = strAssemblyName;
oEventDef.Class = strClassName;
oEventDef.Data = strDefData;
oEventDef.SequenceNumber = intSequenceNo;
oEventDef.Type = SPEventReceiverType.ItemAdded | SPEventReceiverType.ItemUpdated | SPEventReceiverType.ItemDeleting;
oEventDef.Update();
oList.Update();
oWeb.Update();
oWeb.AllowUnsafeUpdates = false;
}
}

public verride oid FeatureDeactivating(SPFeatureReceiverProperties properties)

{
////This will remove from the receiver collection of the list

string strReceiverName = "TestListEventHandler";

using (SPWeb oWeb = (SPWeb)properties.Feature.Parent)

{
SPList oList = oWeb.Lists[strListName];

SPEventReceiverDefinitionCollection oEventDefColl = oList.EventReceivers;

Guid oGuid = new Guid();

foreach (SPEventReceiverDefinition oDef in oEventDefColl)

{

if (oDef.Name == strReceiverName)

oGuid = oDef.Id;

}

if (oGuid != null)

oEventDefColl[oGuid].Delete();

} }

For more about the SPEventReceiverDefinition Class

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

 

  1. Event Handler Class 

Event handler class would inherit the base class and contain the custom code under.....

public cass TestEventHandler: SPItemEventReceiver

public Oerride
void ItemAdded(SPItemEventProperties properties)

public Oerride
void ItemUpdated(SPItemEventProperties properties)

This remains the same.

HaPpY CoDiNg... (Aurum)

Wednesday, April 6, 2011

How to create Item Event Receiver (SPItemEventReceiver)

Another piece of work again. L.. No worries.. would do this in no time. I will be very short and just focus on code. While creating this Event Handler I have used only 3 files.

  1. Feature.xml
  2. Elements.xml
  3. Event Handler class (event handler class inhering from SPItemEventReceiver)

Let us how the code works

Feature.xml
The feature file will remain very simple, only with the basic details.

<?xml version="1.0" encoding="utf-8"?>
<Feature Id="62B66824-3AE2-4320-9949-6B59ED862C64"
Title="TestEventHandler"

Description="Adding/updating/deleting of any item in list"

Version="1.0.0.0"

Hidden="FALSE"

Scope="Web"

DefaultResourceFile="core"

ImageUrl ="NEWSPG.GIF"

xmlns="http://schemas.microsoft.com/sharepoint/">

<
ElementManifests>
<ElementManifest Location="elements.xml"/>
</ElementManifests>
</Feature>

The feature will be very simple and straight forward, nothing special about this except mentioning the element manifest. 

Elements.xml
The elements.xml will hold all the receiver information. The handler assembly and class information would be placed here to execute the events.

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns=http://schemas.microsoft.com/sharepoint/>
<Receivers ListTemplateId="100">
<Receiver>
<Name>AddingEventHandler</Name>
<Type>ItemAdded</Type>
<SequenceNumber>10000</SequenceNumber>
<Assembly>TestEventHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ab011vdd6a7bfaba2</Assembly>
<Class>TestEventHandler.TestEventHandler</Class>
<Data></Data>
<Filter></Filter>
</Receiver>
<Receiver>
<Name>UpdatedEventHandler</Name>
<Type>ItemUpdated</Type>
<SequenceNumber>10000</SequenceNumber>
<Assembly>TestEventHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ab011vdd6a7bfaba2</Assembly>
<Class>TestEventHandler.TestEventHandler</Class>
<Data></Data>
<Filter></Filter>
</Receiver>
<Receiver>
<Name> Delete</Name>
<Type>ItemDeleting</Type>
<SequenceNumber>10000</SequenceNumber>
<Assembly>TestEventHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ab011vdd6a7bfaba2</Assembly>
<Class>TestEventHandler.TestEventHandler</Class>
<Data></Data>
<Filter></Filter>
</Receiver>
</Receivers>
</Elements>

Here on any item added/updated/deleted the event will fire in the class mentioned below <Class>TestEventHandler.TestEventHandler</Class> would handle the events.

Even Handler Class 

Event handler class would inherit the base class and contain the custom code under.....

public class TestEventHandler: SPItemEventReceiver

public override void ItemAdded(SPItemEventProperties properties)

public override void ItemUpdated(SPItemEventProperties properties)

The SPItemEventReceiver class is not instantiated but the item event receiver class of a custom event handler must derive from this class and override its methods for the event types that are handled.

namespace Example_Namespace

{

public class Class_Name : SPItemEventReceiver

{

public override void ItemAttachmentAdded(SPItemEventProperties properties)

{

using (SPSite oSiteCollectionEvent = new SPSite(properties.SiteId))

{
SPWeb oSiteEvent = oSiteCollectionEvent.OpenWeb(properties.RelativeWebUrl);
SPListItemCollection oItemsEvent = oSiteEvent.Lists[properties.ListTitle].Items;
}

using (SPSite oSiteCollection = new SPSite("http://Top_Site"))
{
SPWeb oWebsite = oSiteCollection.OpenWeb("Website_Name");

SPList oList = oWebsite.Lists["Announcements"];

SPListItemCollection collListItems = oList.Items;

SPListItem oItem = collListItems.Add();

oItem["Title"] = properties.UserDisplayName + " added an attachment to " + oItemsEvent[properties.ListItemId].Title + " in list " + properties.ListTitle + " at " + properties.WebUrl;

oItem.Update();

} } } }

HaPpY CoDiNg... (Aurum)

Tuesday, March 15, 2011

Show Quick Launch Menu on SP Web Part Pages

 

This is a very common requirement faced by almost every SharePoint Developer. I was in dilemma whether to put this post or not thus, kept in bay this topic for a while. Smile   Then today I finally decided to add this in to my blog posts.

When we create new web part pages, the page provides the option of adding new web parts inside the specified web part zones. When I tried to create such page with Quick Launch menu, I did not get any option to activate or add the Quick Launch menu by editing the page.

clip_image002

When we create new page, we select a page templates. SharePoint creates new page based on our selected page template and hides all other page elements that are not included in the selected page template. For SharePoint it is always the same page definition and master page, thus the basic structure is always there in the page. We can better understand this if we open the page in the SharePoint Designer. We could see many content place holders which are there in the page but are not visible when the page gets populated. The quick launch menu is placed inside the Place Holder Left Nav Bar (hover over the bottom left side, usually where the quick launch menu remains).

clip_image004

Click the pointer and select Default to Master’s Content

clip_image006

Would get this prompt, click YES

clip_image008

And you could see that the quick launch menu gets visible. Save the page and you are done.....

clip_image004[1]

If you have a more elegant solution – please post a comment… I’ll be happy to hear.

HaPpY CoDiNg... (Aurum)

Sunday, March 13, 2011

Hide "New" document menu item from document library

 

Recently I had to face this requirement of hiding the New from Document Library. I generally disapprove changing the basic functionality/behaviour of SharePoint. At times you have to scratch your head while this kind of changes make SharePoint go crazy and starts behaving erratically.

All these said and done.. I had to implement the requirement.. and the document library was only left with upload option.

Sometimes we can hide the New option by restricting the users with only Read/View permission, but that will also take away the Upload option...

Like a good SharePoint-boy I immediately thought my solution will be creating a new feature that uses the tag for hiding different menu items in SharePoint.

To my surprise I learned that the “new” menu item in the list view web part tool bar is not listed as a in any feature, so it cannot be removed as so.

Finding no other choices, I added a Content Editor Web Part in the Document, created this JS code and added in the Source Editor.

First edit the page by clicking Site Action and the Edit Page

image

Then add a Content Editor Web Part at the same web part zone of the list view.

image

Now modify the web part and get to the source editor and the following JavaScript code.

<div id="Tt" onload="HideNewMenuItem();">

<script language="javascript" type="text/javascript">

_spBodyOnLoadFunctionNames.push("HideNewMenuItem");

function HideNewMenuItem() {

//alert('test script');

try {

if (ctx) {

if (ctx.listBaseType == 1) {

var tables = document.getElementsByTagName("table");

for (var i = 0; i < tables.length; i++) {

if (tables[i].id.indexOf("NewMenu") > 0) {

var element = tables[i];

element.parentElement.parentElement.style.display = "none";

element.parentElement.parentElement.nextSibling.style.display = "none";

} } } } }

catch (e) { }

}

</script>

</div>

The _spBodyOnLoadFunctionNames.push("HideNewMenuItem");add this custom javascript method the on load function collection. The js will not fire if this is not added.

This checks if the current page has a document library view and if so – locate and hide its “new” menu item…

image

Save it and see the New Menu is gone... Viola....

image

If you have a more elegant solution – please post a comment… I’ll be happy to hear.

HaPpY CoDiNg... (Aurum)

Friday, October 8, 2010

Install.bat Part 2

Install.bat for VS 2008

A ready to use install.bat. The Xcopy part has been fully defined since it was not working properly in VS2008.

@SET TEMPLATEDIR="c:\program files\common files\microsoft shared\web server extensions\12\Template"
@SET STSADM="c:\program files\common files\microsoft shared\web server extensions\12\bin\stsadm"
@SET GACUTIL="C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\GacUtil.exe"

Echo Copying files to TEMPLATE directory
xcopy "C:\Partha\Devarea\MyFeatureReceiver\MyFeatureReceiver1\MyFeatureReceiver1\TEMPLATE\*" "c:\program files\common files\microsoft shared\web server extensions\12\Template" /e /y

REM Echo Installing feature
REM %STSADM% -o InstallFeature -filename MyFeatureReceivers\feature.xml -force

REM Echo Uninstalling the DLL from GAC
REM %GACUTIL% /u MyFeatureReceiver1

Echo Installing the DLL in GAC
Echo %GACUTIL%
%GACUTIL% /i "C:\Partha\Devarea\MyFeatureReceiver\MyFeatureReceiver1\MyFeatureReceiver1\bin\Debug\MyFeatureReceivers.dll"

REM Echo Restart IIS Worker Process IISRESET
REM IISRESET


http://blah.winsmarts.com/2008-7-Authoring_SharePoint_2007_Workflows_using_VS2008.aspx
http://msdn.microsoft.com/en-us/library/bb466224(office.12).aspx

Install.bat - With Application pool Recycle in Visual Studio 2008

ECHO Installation in progress.........

@SET TEMPLATEDIR="C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE"
@SET STSADM="C:\program files\common files\microsoft shared\web server extensions\12\bin\stsadm"
@SET GACUTIL="C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\gacutil.exe"
@SET APPPOL="C:\WINDOWS\system32\cscript.exe"
@SET IISVBS="C:\WINDOWS\system32\iisapp.vbs"

ECHO Copying files..........
rem xcopy /e /y TEMPLATE\* "C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE"
xcopy /e /y TEMPLATE\* %TEMPLATEDIR%
ECHO Uninstalling the DLL from GAC
%GACUTIL% /u SimpleCustomApplicationPage1

ECHO Installing the DLL in GAC
%GACUTIL% /i "E:\Partha Projects\SP2007\Custome Application Pages\SimpleCustomApplicationPage1\SimpleCustomApplicationPage1\bin\Debug\SimpleCustomApplicationPage1.dll"

REM If we need to restart only the AppPool then
REM SET /P AppPoolName=[Please Enter the application pool name]
REM %APPPOL% %IISVBS% /a %AppPoolName% /r

ECHO Restart IIS Application Pool - Worker Process IISRESET
%APPPOL% %IISVBS% /a "SharePoint - 7070" /r

Another one
@echo off
ECHO Installation in progress.........

@SET TEMPLATEDIR="C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE"
@SET STSADM="C:\program files\common files\microsoft shared\web server extensions\12\bin\stsadm"
@SET GACUTIL="C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\gacutil.exe"
@SET APPPOL="C:\WINDOWS\system32\cscript.exe"
@SET IISVBS="C:\WINDOWS\system32\iisapp.vbs"

ECHO Copying files..........
xcopy /e /y TEMPLATE\* %TEMPLATEDIR%
ECHO Uninstalling the DLL from GAC
%GACUTIL% /u MultiLingualListDefinition

ECHO Installing the DLL in GAC
%GACUTIL% /i "E:\Partha Projects\SP2007\CustomListDefinition\MultiLingualListDefinition\bin\Debug\MultiLingualListDefinition.dll"

Echo Installing Feature.......
%STSADM% -o installfeature -filename MLContentType\feature.xml -force
%STSADM% -o installfeature -filename MLStringListDefinition\feature.xml -force

REM Echo Activating Features...........
REM %STSADM% -o activatefeature -filename MLContentType\feature.xml
REM %STSADM% -o activatefeature -filename MLStringListDefinition\feature.xml


REM If we need to restart only the AppPool then
REM SET /P AppPoolName=[Please Enter the application pool name]
REM %APPPOL% %IISVBS% /a %AppPoolName% /r

ECHO Restart IIS Application Pool - Worker Process IISRESET
%APPPOL% %IISVBS% /a "SharePoint - 7070" /r

CabLib – Error running MakeCab.exe

CabLib – Error running MakeCab.exe
Could not load file or assembly 'CabLib, Version=6.9.26.0, Culture=neutral, Publ
icKeyToken=85376ef9a48d191a' or one of its dependencies
I was trying to create a solution package for SharePoint. Thus, planned to use the Makecab.exe to create the cab file. Upss!! got this error while running the makecab.exe /f MyAppPackage.ddf
Building the solution - please wait
Saving the Manifest.xml file
Creating the WSP file
Could not load file or assembly 'CabLib, Version=6.9.26.0, Culture=neutral, PublicKeyToken=85376ef9a48d191a' or one of its dependencies. An attempt was made to load a program with an incorrect format. It seemed that the Dll could not be loaded
Sometimes this could happen while running wspbuilder.exe also.
Investigation:
1. I have the CabLib.dll file in the same directory as wspbuilder.exe
2. cabinet.dll exists in the windows\system32 directory.
3. The CABLIB.DLL is a C++ library and therefore you have to use the right version of it when you are using 32 or 64 bit windows server systems.
Solution :
Thought of one very simple solution, normally whenever I get stuck with such problem I use that only…. Putting the dll in the GAC haaaaaa. Found the dll from this location.
C:\Program Files\WSPTools\WSPBuilderExtensions\Resources\x86]
CabLib.dll
Dropped in Assembly file….. i.e. GAC. And it worked…. That’s all….
HaPpY CoDiNg………….
Partha (Aurum)