Friday, August 6, 2010

Comparing Sharepoint backup and STSADM backup

Hi All,

I have been working with the Administration part of Sharepoint and have been through many issues while restoration of backup taken using both STSADM and Sharepoint Central Admin Backup.

Scenario 1:
If we use STSADM the disadv we would be facing is it would delete all the Task List Items where as if we go with Central Admin Backup restoration then it would restore the Task List Items too.

Scenario 2:
Where when there is a scenario of creating more than a single site or a series of operations to be done then I recomment going for STSADM and it would make our lifes easier rather than going for Central Admin Site.

Scenario 3:
We generally have scheduled backup going on the servers which you could do using STSADM but not using Central Admin Backup.
Backup a sitecollection
***********************

ECHO ON
SET SITECOLLURL="mysitecollectionurl"
SET FILENAME="mybackup.bak"
SET STSADM="C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\bin\stsadm"
REM ----- Execute Site Collection Backup -----
%STSADM% -o backup -url %SITECOLLURL% -filename %FILENAME%
%STSADM% -o execadmsvcjobs
***********************


Restore a sitecollection
***********************
ECHO ON
SET SITECOLLURL="mysitecollectionurl"
SET FILENAME="mybackup.bak"
SET STSADM="C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\bin\stsadm"
REM ----- Execute Site Collection Restore -----
%STSADM% -o restore -url %SITECOLLURL% -filename %FILENAME%
%STSADM% -o execadmsvcjobs
***********************
 
 
This could be setup as windows scheduler and run every Sunday at 12:00AM which would take a backup.
 

Sharepoint Event Handlers

Hi All,

I have been working quite a few days on Sharepoint Event Handlers and have faced few problems while programming and have found the below very interesting and useful verymuch.

Please do consider the below issues I have faced and figured out these are the only things which are possible with Event Handlers.


For a List:

List                         ItemAdding  ItemAdded ItemUpdating  ItemUpdated  ItemDelting ItemDeleted
BeforeProperties      No value      No value        No value          NoValue         Novalue       Novalue
AfterProperties       New value    New value   Changed value   ChangedValue   Novalue      Novalue
properties.ListItem    Null           New value   Originalvalue     ChangedValue  Originalvalue   Null

For a Library:

Library
BeforeProperties
AfterProperties
properties.ListItem

ItemAdding

No value

No value

Null



ItemAdded

No value

No value

New value



ItemUpdating

Original value

Changed value

Original value



ItemUpdated

Original value

Changed value

Changed value



ItemDeleting

No value

No value

Original value



ItemDeleted

No value

No value

Null



Please add-in your thoughts/corrections if any.

This has really helped me a lot.

DateTime object convertion

Hi,

While I was working on Sharepoint requirements, I have faced a scenario of rading the DateTime column, where my problem was I require only date but the DateTime object reference which I have got after reading from the list's column value holds both Date as well as Time.

So I came across the below procedure to resolve my problem.

**************************************

DateTime.Parse(item[dateFieldName].ToString()).ToString("MM/dd/yyyy");

**************************************


other way of doing the same is as below:
 
***************************************
string dateString = "Mon 16 Jun 8:30 AM 2008";

string format = "ddd dd MMM h:mm tt yyyy"; DateTime dateTime = DateTime.ParseExact(dateString, format,
CultureInfo.InvariantCulture);
Console.WriteLine(dateTime);

**************************************
 
This has resoved my problem.
 

Thursday, August 5, 2010

Memory Leaks in Sharepoint

Hi Folks,

I faced quite a few issues while writing the webparts and other code snippets and found memory leaks while we were using Object Model for sharepoint programming.

Please cosider the below scenario:

Scenario 1:
----------------------------------------------------------------------------------------------
SPSite site = new SPSite("site URL");
SPWeb web = site.OpenWeb();
.....................
................

Note: Here i am not disposing any objects

But I need to do that, so rather than disposing explicitly, we could follow the below approach

***************************
using(SPSite site = new SPSite("site URL"))
{
using(SPWeb web = site.OpenWeb())
{
.................
...............
}
}
**************************

otherwise we could write the same program as below:

***********************************
String str;

SPSite oSPSite = null;
SPWeb oSPWeb = null;
try
{
oSPSite = new SPSite("http://server");
oSPWeb = oSPSite.OpenWeb(..);
str = oSPWeb.Title;
}
catch(Exception e)
{
//Handle exception, log exception, etc.
}
finally
{
if (oSPWeb != null)
oSPWeb.Dispose();
if (oSPSite != null)
oSPSite.Dispose();
}
*********************************

This has solved many of the memory leak issues which I was facing.




Scenario 2:
----------------------------------------------------------------------------------------------
This is a case whenever we access the listCollection.Items.Count/web.Lists.Count several times.

Consider the below scenario:
***********************************
for(int i=0;i<listCollection.Items.Count;i++)
{
...............................
...........................
}
***********************************
Observation: for each and every iteration it gets the Item count in the list and checks with the value of variable "i", which would some times cause performance issues when the list size increases.
Resolution:
**********************************
int itemCount = listCollection.Items.Count;
for(int i=0;iitemCount;i++)
{
...............................
...........................
}
**********************************
Observation:First we need to assign the item count to some variable to avoid multiple times calculation.


Scenario 3:
------------------------------------------------------------------------------------------------------------------
We basically require only few items to be returned while querying i.e., while we are using SPQuery object I require only only few rows from the list to be retrieved.

Consider the below scenario:
I require the top 3 rows in a list
********************************
SPQuery query = new SPQuery();
query.Query("actual query copied from CAML Builder");
list.getItems(query);
********************************
Observation: This would return all the items in the list irrespective of what i needed and even in the CAML query there is no possibility for limiting the rows.

That we could do using the SPQuery object as below:
Resolution:
********************************
SPQuery query = new SPQuery();
query.Query("actual query copied from CAML Builder");
query.RowLimit(3);
list.getItems(query);
********************************
Observation: using RowLimit I would be able to get only limited rows what I was intended to retrieve.

Scenario 4:
----------------------------------------------------------------------------------------------
We require only few columns while retrieveing the list items using the SPQuery object.

Consider the below scenario:
********************************
SPQuery query = new SPQuery();
query.Query("actual query copied from CAML Builder");
list.getItems(query);
********************************
Observation: This would return all the columns in the list irrespective of what are all the columns which we require.
Resolution:
********************************
SPQuery query = new SPQuery();
query.Query("actual query copied from CAML Builder");
query.ViewFields = "";
list.getItems(query);
********************************
Observation:This would return the required columns and we wouldnt face any performance issues.


Please feel free to addon your comments if any.
Any clarification please post me back

Getting users from multiple people picker column

Hi All,

I have been working on Sharepoint Portal quite a few requirements and one of it made me write a sample snippet for sending emails to all the "Assigned To"/"Cc" column users.

Now below is the code for reading all the users present in the multiple people picker column in which not only users but also groups could be selected.
***********************************
SPFieldUserValueCollection CcUsers = (SPFieldUserValueCollection)properties.ListItem["Cc"];
if (CcUsers != null)
{
foreach (SPFieldUserValue val in CcUsers)
{
if (val.User != null)
CcUserEmails += (val.User.Email + ";");
else
{
SPGroup grp = web.Groups.GetByID(val.LookupId);
foreach (SPUser user in grp.Users)
{
CcUserEmails += (val.User.Email + ";");
}
}
}
}
***********************************
This has resolved my coding.
Please post your comments or issues if any.

Create a Sample Timer Job

Create a Sample Timer Job
Create your own timer JobMOSS Timer JobsIn previous versions of SharePoint (or other platforms), if you had some task you wanted to perform on a scheduled basis, you'd have to either create a console EXE and schedule it to run via Windows Task Scheduler (ala AT.EXE) or create a Windows Service that went to sleep for a period of time. In order to install (and maintain) these tasks, you had to have console access to your production SharePoint (or other app) servers... something IT or admins wouldn't easily hand out.Addressing this issue, Microsoft has added something called timer jobs to Microsoft Office SharePoint Server (MOSS) 2007. Microsoft uses timer jobs to do things like dead web cleanup (purging unused sites from site collections) among others. To see what other timer jobs are out there, from Central Administration, click Operations and then Timer Job Definitions. Not only does Microsoft use timer jobs in MOSS, but you can create your own custom timer jobs to do your own scheduled tasks. What's nice about this is once your timer job has been installed (something you can easily do with a solution & a feature), you can view it's status through Central Administration and even disable/enable it... all without console access to your production servers! Another cool thing is that when your job runs, MOSS passes it the GUID of the content database for the site the job is registered with. You can use this GUID to obtain a reference to a content database, then a site collection, and finally a site within the collection (SPWeb).How do you build one? Well, unfortunately the documentation is lacking here... there isn't a single article in the SDK talking about creating custom timer jobs and the necessary objects aren't well documented either.Everything surrounds the Microsoft.SharePoint.Administration.SPJobDefinition object. Create a new class that inherits from SPJobDefinition, implement a few constructors and a single method: Execute(Guid). I created a simple timer job that (assuming it's associated with a WSS site created using the Team Site template and there's a Tasks list in the root of the site) creates a new task every 5 minutes when the job is enabled. Here's what the constructors look like ([update 1/11 12p] added a default empty constructor[/]):
1: public TaskLoggerJob ()2: : base(){3: }4: public TaskLoggerJob (string jobName, SPService service, SPServer server, SPJobLockType targetType)5: : base(jobName, service, server, targetType) {6: }7: public TaskLoggerJob (string jobName, SPWebApplication webApplication)8: : base(jobName, webApplication, null, SPJobLockType.ContentDatabase) {9: this.Title = "Task Logger";10: }
Now, after you build the assembly containing your custom timer job and add it to the GAC (a requirement), you need to associate it with a specific site, site collection, web application, or farm and specify a schedule for when it should run. Ideally I'd like to do this with STSADM.EXE, but no such command exists (custom command opportunity out there!). Another way is to do this through the object model. Because I want to minimize any console access requirements, I'll do this in a feature by implementing the FeatureActivated event. To do this, you create an instance of your job, set the schedule, and call update like so:1: // get a reference to our job in the GAC2: TaskLoggerJob taskLoggerJob = new TaskLoggerJob("Task Logger", site.WebApplication);3: // set the execution schedule4: SPMinuteSchedule schedule = new SPMinuteSchedule();5: schedule.BeginSecond = 0;6: schedule.EndSecond = 59;7: schedule.Interval = 5;8: taskLoggerJob.Schedule = schedule;9: //update the job10: taskLoggerJob.Update();
That's it! Course you should take this a step further by packaging all this up in a solution that will deploy the assembly to the GAC and install a feature. Then, upon activating the feature, it will associate the web with the timer job. Conversely, upon deactivating the feature, it removes the timer job. Very slick!Creating custom sharepoint timer jobsA few weeks back I posted about how you can create custom timer jobs for use in the latest release of SharePoint to perform scheduled tasks. However, considering there have been almost 40 comments to the post in the last three weeks, I figured the post needed some clarification (duh, ya think?).The first thing you need to do is create a class that inherits from the Microsoft.SharePoint.Administration.SPJobDefinition class. To implement this class, you need to create a few constructors and override the Execute() method, like so:
1: namespace AndrewConnell.TaskLogger {2: public class TaskLoggerJob : SPJobDefinition{3: 4: public TaskLoggerJob ()5: : base(){6: }7: 8: public TaskLoggerJob (string jobName, SPService service, SPServer server, SPJobLockType targetType)9: : base (jobName, service, server, targetType) {10: }11: 12: public TaskLoggerJob (string jobName, SPWebApplication webApplication)13: : base (jobName, webApplication, null, SPJobLockType.ContentDatabase) {14: this.Title = "Task Logger";15: }16: 17: public override void Execute (Guid contentDbId) {18: // get a reference to the current site collection's content database19: SPWebApplication webApplication = this.Parent as SPWebApplication;20: SPContentDatabase contentDb = webApplication.ContentDatabases[contentDbId];21: 22: // get a reference to the "Tasks" list in the RootWeb of the first site collection in the content database23: SPList taskList = contentDb.Sites[0].RootWeb.Lists["Tasks"];24: 25: // create a new task, set the Title to the current day/time, and update the item26: SPListItem newTask = taskList.Items.Add();27: newTask["Title"] = DateTime.Now.ToString();28: newTask.Update();29: }30: }31: }
As you can see, this job does nothing important but add a new item to a Task list every time it's executed. Now that you have the job built, you need to get it registered. Unfortunately the only way to do this is through code, but it sure would be one heck of a candidate for a custom STSADM command. Anyway, since we don't have that today, I like to use the feature activated & deactivated events to install/uninstall my custom jobs.To do this, you have to create another class that inherits from the Microsoft.SharePoint.SPFeatureReceiver class and implement the FeatureActivated & FeatureDeactivated event handlers like so:
1: namespace AndrewConnell.TaskLogger {2: class TaskLoggerJobInstaller : SPFeatureReceiver {3: conststring TASK_LOGGER_JOB_NAME = "TaskLogger";4: publicoverridevoid FeatureInstalled (SPFeatureReceiverProperties properties) {5: }6: 7: publicoverridevoid FeatureUninstalling (SPFeatureReceiverProperties properties) {8: }9: 10: publicoverridevoid FeatureActivated (SPFeatureReceiverProperties properties) {11: SPSite site = properties.Feature.Parent as SPSite;12: 13: // make sure the job isn't already registered14: foreach (SPJobDefinition job in site.WebApplication.JobDefinitions) {15: if (job.Name == TASK_LOGGER_JOB_NAME)16: job.Delete();17: }18: 19: // install the job20: TaskLoggerJob taskLoggerJob = new TaskLoggerJob(TASK_LOGGER_JOB_NAME, site.WebApplication);21: 22: SPMinuteSchedule schedule = new SPMinuteSchedule();23: schedule.BeginSecond = 0;24: schedule.EndSecond = 59;25: schedule.Interval = 5;26: taskLoggerJob.Schedule = schedule;27: 28: taskLoggerJob.Update();29: }30: 31: publicoverridevoid FeatureDeactivating (SPFeatureReceiverProperties properties) {32: SPSite site = properties.Feature.Parent as SPSite;33: 34: // delete the job35: foreach (SPJobDefinition job in site.WebApplication.JobDefinitions) {36: if (job.Name == TASK_LOGGER_JOB_NAME)37: job.Delete();38: }39: }40: }41: }
Now... to get it working, all you need to do is:1. Deploy the strongly named assembly to the GAC.2. Reset IIS (required for SharePoint to "see" the new timer job in the GAC).3. Create a feature specifying the receiver class and assembly that contains the event receivers.4. Install the feature.5. Activate the feature.This sample timer job assumes it's running within the context of a WSS v3 site that has a list created with the Tasks list template in the root web within the site collection (or, just create a Team Site at the root of your site collection).Once you activate the feature, 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. Wait for five minutes or so (the schedule this sample is using) to see if it's running. You should start to see items showing up in the Tasks list in the root site in your site collection.Here's a Visual Studio 2005 solution that includes everything you need to create a custom timer job. Note that I used the technique I described in this article to modify the Visual Studio project to create the WSP file for me:» TaskLogger_CustomTimerJob.zipOr, you can use this Windows SharePoint Solution Package (*.WSP) to deploy the prebuilt timer job used in this article (handles steps 1-4 above):» AndrewConnell.TaskLoggerJob.zip (unpack the ZIP to get the WSP)To deploy the WSP file, simply add it to the solution store using STSADM (using the following command) and then deploy it to the desired site:stsadm –o addsolution –filename AndrewConnell.TaskLoggerJob.wspUsing locks in Custom MOSS Timer JobsMicrosoft Office SharePoint Server(MOSS) 2007 provides both out of box timer jobs as well as the option to create your own custom timer.The MOSS OWSTimer.exe process controls and executes all timer definition jobs for SharePoint.Custom timer jobs can be created using either a feature or using a solution.Microsoft.SharePoint.Administration.SPJobDefinition class contains the definition for the MOSS timer jobs. MOSS passes the GUID of the content database for the site the job is registered with. You can use this GUID to obtain a reference to a content database, then a site collection, and finally a site within the collection (SPWeb).The class containing the invocation code for the timer jobs must inherit from the Microsoft.SharePoint.Administration.SPJobDefinition class. The constructors need to be created and the Execute() method must be overridden as mentioned below. The Execute() method is overridden for performing the custom activity that the user has planned to do using the timer jobs. The Execute() is invoked by the MOSS timer services but if there is no lock applied on the code then concurrency issues arise if different users are planning to trigger the timer job at the same time. To overcome concurrency issues the Execute() code must be locked by the process that is executing and the other concurrent process must wait till the lock is removed.Scenario: Users in an organization are planning to synchronize lists(which they have access on) in a MOSS web application. They are performing the activity by using a UI (ASP.Net web application running under MOSS context) and creating timer jobs that in turn run and complete the process. Users who are requesting for the sync activity are notified with a mail in the end on the success or failure of the job. In our current scenario we are planning to use the included property bag (SPJobDefinintion.Properties) to store your custom properties. The property bag stores the requestor alias(UserAlias) and the SiteUrl. namespace Infosys.Blogs
{
public class TimerJobClass : SPJobDefinition{
/// /// Base class constructor
/// public TimerJobClass() : base(){
}
public TimerJobClass(string jobName, SPService service, SPServer server, SPJobLockType targetType) : base (jobName, service, server, targetType)
{
}
/// /// Constructor that accepts the JobName,SPWebapplication
/// public TimerJobClass(string jobName, SPWebApplication webApplication) : base (jobName, webApplication, null, SPJobLockType.ContentDatabase) { } /// /// Called by MOSS when the Job is kicked off for execution
/// /// public override void Execute(Guid contentDbId){lock (timerLock)
{
//Fetch the value from the Job PropertyBagif (this.Properties.ContainsKey(JobPBValue)){fetchJobPB = this.Properties[timerJobName].ToString();} string[] jobPropertyBag = fetchJobPB.Split(','); string siteUrl = jobPropertyBag[jobPropertyBag.Length - 0];string userAlias = jobPropertyBag[jobPropertyBag.Length - 1];//Queue at the Root site collection level of the web applicationcurrentSite = new SPSite(siteUrl);currentSite = new SPSite(currentSite.Url);currentWeb = currentSite.OpenWeb();
//Body of code - writes to a list..//End of code - writes to a listSPUtility.SendEmail(currentWeb, false, false, userAlias, "Status of Timer Job" + this.Name, “The Job is Completed”);
}

Getting the SPWeb object dynamically in WebParts

Hi All,
I have been working on some sharepoint webparts these days and found some queeky thing which people do regularly which I have listed below and even provided the resolution for it.
Generally, people get adhere to hardcode the URL's of different portals in the webparts which is quite a wrong thing. Instead we could do get the URL of the Site dynamically.

Wrong Approach:
***************************
public void RenderControls()/RenderContents(){
SPSite siteColl = new SPSite(":">http://:/");
SPWeb webSite = siteColl.OpenWeb();
.........
.......
}
***************************


Right Approach:
***************************
public void RenderControls()/RenderContents(){
//SPSite siteColl = SPContext.Current.Web.Site;
//SPWeb web = siteColl.RootWeb;
SPWeb web = SPContext.Current.Web;
..................
................
}
***************************

If you follow this process you wouldnt be in trouble if you add the same webpart in different portals across sites. It would work as dynamic one.