Sunday, September 25, 2011

Which w3wp.exe process belongs to which App Pool

When you are debugging a ASP.NET web application which is hosted on IIS, you need to attach the particular worker process in Visual Studio to start debugging. The process to attach a process J is go to Tools > Attach Process or use shortcut key Ctrl+Alt +P. The process window will show the worker process (w3wp.exe) which is currently running on IIS. You need to select the process and click on attach button to start the debugging. Problem starts when you have multiple worker process running on IIS. If you have multiple sites hosted on IIS and each site having their own application pool then you will see the list of all worker process in the Process Attach window.

Whenever we create a new Application Pool, the ID of the Application Pool is being generated and it’s registered with the HTTP.SYS (Kernel Level of IIS). Thus, whenever HTTP.SYS  receives any request from any web application, it checks for the Application Pool and based on the application pool ID, it send the request to appropriate worker process

I will straight way show you how to do the same on command prompt for IIS 6 & 7:

 IIS 6:

1.       Go to command prompt (run->cmd)

2.       Go to system32, the prompt should be like -

Write C:\>cd WINDOWS\system32 and you will reach C:\WINDOWS\system32>

Since the cscript.exe  resides here.

3.       Next command is – cscript iisapp.vbs

IIS 7:

From IIS 7.0 you need you to run IIS Command Tool ( appcmd ) .
1.  Start > Run > Cmd
2. Go To Windows > System32 > Inetsrv
3. Run appcmd list wp

This will show you list worker process that is running on IIS 7.0 in the similar format of IIS 6.0

And you get all the w3wp.exe with process id with AppPool id.

C:\WINDOWS\system32>cscript iisapp.vbs

Microsoft (R) Windows Script Host Version 5.6

Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

 

W3WP.exe PID: 8104   AppPoolId: SharePoint - 7011

W3WP.exe PID: 8080   AppPoolId: SharePoint Central Administration v3

W3WP.exe PID: 7600   AppPoolId: SharePoint - 7010

W3WP.exe PID: 148   AppPoolId: MyWebApp

Now you have the liberty to attach the desired process only. J

Thanks for reading. If you have some other explanation – please post a comment… I’ll be happy to hear.

...HaPpY CoDiNg

Partha (Aurum)

References:

Monday, September 19, 2011

How get SharePoint 2007 SpListItem DispForm Url

We need to implement a bit of tweaking to the List Item to get the Display Form url. I wonder why this was not provided very straight forward. Okay, the trick is need to get to PAGETYPE and then get the url. See the below code stub for details. In this similar process we can get the view/edit page urls as well.

 

#region Get Display Form URL

        private string GetDisplayFormURl()

        {

 

            using (SPSite site = new SPSite("http://yoursite"))

            {

                using (SPWeb web = site.OpenWeb())

                {

                    SPList list = web.Lists[0];

                    SPListItem item = list.Items[0];

                    ////Now we have two options to concatenate the string.

                    string ItemDispFormUrl = String.Concat(item.Web.Url, "/",item.ParentList.Forms[PAGETYPE.PAGE_DISPLAYFORM].Url, "?id=", item.ID.ToString());

                    string DisplayFromUrl = item.Web.Url + "/" + item.ParentList.Forms[PAGETYPE.PAGE_DISPLAYFORM].Url + "?id=" + item.ID.ToString();

                    return DisplayFromUrl;

                }

            }

        }

 #endregion

 

Thanks for reading. If you have some other explanation – please post a comment… I’ll be happy to hear.

...HaPpY CoDiNg

Partha (Aurum)

 

Friday, September 16, 2011

How to Get SPUser Collections from SPListItem

In my previous post I have shown the code snippet to fetch SPUser from ListItem, now at times the user field may contain more than one user. It all depends on how you configure the list column. If you check the box for multiple user then the field will allow to add multiple users. In such a scenarios you need to use the below code stub.  

# #region Get SP User(s)

        private List<SPUser> GetSPUser1(SPListItem item, string ColumnName)

        {

            ////Get field/column from List Item

            SPFieldUser field = item.Fields[ColumnName] as SPFieldUser;

            List<SPUser> MySPUserCollection = new List<SPUser>();

            if (field != null && item[ColumnName] != null)

            {

                ////If the Field/Column allows multiple users, then the field will have a collection of User values

                SPFieldUserValueCollection oFieldColl = field.GetFieldValue(item[ColumnName].ToString()) as SPFieldUserValueCollection;

                ////See if the collection has got users

                if (oFieldColl.Count > 0)

                {

                    for (int i = 0; i <= oFieldColl.Count; i++)

                    {

                        MySPUserCollection.Add(oFieldColl[0].User);

                    }

                }

            }

            return MySPUserCollection;

        }

        #endregion

 

Thanks for reading. If you have some other explanation – please post a comment… I’ll be happy to hear.

...HaPpY CoDiNg

Partha (Aurum)

References:

 

Wednesday, September 14, 2011

How to get SPUser from SPListItem

This small method will return you the SPUser from any ListeItem. The second parameter is the column which contains the User. In my next snippet I will provide the method for the collection of users.

#region Get SP User

        private SPUser GetSPUser(SPListItem item, string ColumnName)

        {

            SPFieldUser field = item.Fields[ColumnName] as SPFieldUser;

 

            if (field != null && item[ColumnName] != null)

            {

                SPFieldUserValue fieldValue = field.GetFieldValue(item[ColumnName].ToString()) as SPFieldUserValue;

                if (fieldValue != null)

                {

                    return fieldValue.User;

                }

            }

            return null;

        }

        #endregion

 

 

 

Same piece of code, not in a method

SPFieldUser userFieldOwnedBy = (SPFieldUser)oWeb.Lists[“ListName”].Fields.GetField(“FieldAssignedTo”);

                SPFieldUserValue filedValueOwnedBy = (SPFieldUserValue)userFieldOwnedBy.GetFieldValue(“FieldAssignedTo”);

SPUser userAssignedTo = filedValueOwnedBy.User;

 

Thanks for reading. If you have some other explanation – please post a comment… I’ll be happy to hear.

...HaPpY CoDiNg

Partha (Aurum)

Wednesday, September 7, 2011

Creating MOSS Custom Timer Job

As always, I would take this opportunity to define what we are intending to explain in this article. It is SharePoint Timer job and to add a surprise factor, it would be custom developed. To be very honest I have often observed SharePoint Timer jobs becomes a head ache, since debugging is very cumbersome. See my other article Creating Custom SharePoint Timer Job, I have described in details all the steps of developing timer jobs. In this article I will be very crisp in developing a timer job.

 

 

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

 

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

 

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

 

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 feature receiver class would be the next stop to look into

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();

 

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

 

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, we 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>

 

1.    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 Starts ******************************

 

Thanks for reading. If you have some other explanation – please post a comment… I’ll be happy to hear.

...HaPpY CoDiNg

Partha (Aurum)

 

References:

http://www.codeguru.com/cpp/misc/misc/microsoftofficeoutlook/print.php/c14133