Prevent SharePoint solutions from getting Deployed Globally

We must have noticed that for certain solution packages (.wsp), SharePoint only provides the option to Deploy it globally. This is a big drawback for applications that were meant to target certain Web Applications only.Due to the fact that the wsp is deployed globally, an IIS Pool recycle will be performed bringing down all the WebApplications, even though the current solution package (.wsp) was targeting only some of them (or even one of them).

To avoid this, simply follow the following steps:

=> In Visual Studio load your project.
=> Open Solution Explorer.
=> Double Click on the Package.package.
=> Once it’s opened, click on the Advanced option of this package
=> The Additional Assemblies screen will show up. Then, click the option, “Add Existing Assembly“. [Note: This option is valid only if your solution package does not depend on multiple assemblies and you can just add the current project’s dll. Otherwise, click on “Add Assembly from Project Output“.]

=> If you have selected the first option, “Add Existing Assembly” then, select the source path, of your current dll.
=> If you have selected the option, “Add Assembly from Project Output” then you have to select the source project instead of just a dll.
=> The location field will be automatically updated.
=> Leave the deployment target at GlobalAssemblyCache.
=> Copy the name of the dll from the Location field without “.dll” part.
=> Under SafeControls, Click to add a new item.
=> Double-Click the Namespace field and paste the item you just copied. Do the same for Assembly Name field.

=> Click OK to close the window.
=> You should now be able to see the following screen.

=> Select your project in Solution Explorer, press F4 and set “Include Assembly In Package” as False.

Finally, deploy your solution and check the same in Central Administration. You can now see that your wsp has been deployed to a given Web Application only.

Create a SharePoint Timer Job

Create a Blank SharePoint project in Visual Studio.Enter your site url and validate.

Add a new class say, TestTimer.

All timers must inherit from the class, Microsoft.SharePoint.Administration.SPJobDefinition. Following is the code sample for our TestTimer class.


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

namespace SharePointTimerSample
{
    class TestTimer : SPJobDefinition
    {
        public TestTimer()
            : base()
        {
        }

        public TestTimer(string jobName, SPService service, SPServer server, SPJobLockType targetType)
            : base(jobName, service, server, targetType)
        {
        }

        public TestTimer(string jobName, SPWebApplication webApplication)
            : base(jobName, webApplication, null, SPJobLockType.Job)
        {
            this.Title = "My Test Timer Job";
        }

        protected override bool HasAdditionalUpdateAccess()
        {
            return true;
        }

        public override void Execute(Guid contentDbId)
        {
            //Write your main code here
        }
    }
}

The main functionality of our Timer job has to be laid down in the “Execute” method. It is this method, which will get called periodically by the timer after the completion of its given time interval.

Now, add a new Feature to your project.

Set the scope of the timer as per your requirement. Here, we’re going to set its scope to the site level. You can also set the name of your timer job here. Plz note that this is the name that will be displayed under the SiteCollection features option and is not the name of your wsp. The wsp’s name is going to be the name of your project.

Add a EventReceiver to our newly created Feature.

It is at the EventReceiver, we define the activities that needs to be performed while activating or deactivating the timer job. Even the time interval is also defined here.


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

namespace SharePointTimerSample.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("e61e62e9-5b30-4c8b-ad03-402056f835e3")]
    public class Feature1EventReceiver : SPFeatureReceiver
    {
        // Uncomment the method below to handle the event raised after a feature has been activated.

        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                SPSite site = properties.Feature.Parent as SPSite;
                int userid = site.RootWeb.CurrentUser.ID;

                // make sure the job isn't already registered  
                site.WebApplication.JobDefinitions.Where(t => t.Name.Equals("List_JOB_NAME")).ToList().ForEach(j => j.Delete());

                // install the job  
                TestTimer listLoggerJob = new TestTimer("List_JOB_NAME", site.WebApplication);

                //SPDailySchedule schedule = new SPDailySchedule();
                //schedule.BeginHour = 17;
                //schedule.BeginMinute = 0;
                //schedule.BeginSecond = 0;
                //schedule.EndSecond = 59;
                //schedule.EndMinute = 59;
                //schedule.EndHour = 0;
 
                SPMinuteSchedule schedule = new SPMinuteSchedule();
                schedule.BeginSecond = 0;
                schedule.EndSecond = 59;
                schedule.Interval = 5;
                
                listLoggerJob.Schedule = schedule;
                listLoggerJob.Update();
            });
        }


        // Uncomment the method below to handle the event raised before a feature is deactivated.

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                SPSite site = properties.Feature.Parent as SPSite;

                // delete the job  
                site.WebApplication.JobDefinitions.Where(t => t.Name.Equals("List_JOB_NAME")).ToList().ForEach(j => j.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)
        //{
        //}
    }
}

Finally, select your Feature in the Solution Explorer, and change, “Activate On Default” to False and “Always Force Install” to True.

That’s it. Next, deploy your solution and activate the feature from the “Site Collection features” option of your site. [As we set the scope to Site level.]

Check the Process ID of a Site Deployed on an IIS Server

To debug a SharePoint site (or, asp.net) hosted in IIS, we need to attach the corresponding w3wp to Visual Studio. However, if you have multiple sites running in your IIS, you’ll find multiple w3wp processes [Worker Process] running in your task manager. The problem is that you can never tell to which site, a given w3wp process is associated with merely looking at the task manager.Alternatively, we can attach all the process to visual studio but it will only make it slower. To identify the actual process, we can simply run a command at the command prompt or we can directly get the info from the IIS Manager.

Command Prompt

Open Command Prompt with ‘Run as administrator‘.
Navigate to the path:
C:\Windows\System32\inetsrv\

For IIS 6

Run the command,

iisapp.vbs

For IIS 7

Run the command,

appcmd list wp

IIS Manager

  • Go to run and type, inetmgr and press enter.
  • In the IIS Manager, select the server name in the left panel.
  • Then open “Worker Processes” from the main screen, under the IIS section.
  • You can see that the unique Process ID has been mentioned against each app pool entry.

NOTE: Application pools by default (even in IIS 6) will only spawn a worker process (w3wp.exe) on the first request to a web-application hosted by that particular pool. The w3wp.exe instance will then remain alive for another 20 minutes (assuming default settings) and if no other requests for that application pool come in, IIS will shut the w3wp.exe down – remark that the pool is still active. The setting that controls this is the Idle Timeout in both IIS 6 and 7.

http://linqto.me/IISArchP1
http://linqto.me/IISArchP2