Thursday, July 31, 2008

Customising Sharepoint Alerts (SPAlert)

Have you ever wanted to modify "Alert" Setting in SharePoint 2007 based on certain criteria. We had a requirement recently, from a client, to modify alert filters in a very specific way. They wanted to change not the functioning but the filters, and they wanted the filters to be generated at run time based on the content type.

Alerts[Info: MSDN SPAlert] can be created based on context of a SPWeb or of SPUser. Take a look at the snipped below.

From SharePoint User
SPAlert user = //fetch SPUser
SPAlert alert = user.Alerts.Add();

From SharePoint Web
SPWeb web = //fetch web
SPAlert alert = web.Alerts.Add();

Bare in mind alerts are user/group centric. When an alerts is created based on web alert object does not have user associated to it. It is imperative that we supply SPUser object. Code below does exactly that.

alert.User = user;

There are other properties one can associate with alters, such as,

* frequency of alters
* alert template
* alert type [based on List or ListItem]
  • Custom
  • List
  • Item
* event to which the alert applies
  • Add
  • All
  • Delete
  • Discussion
  • Modify
and many more.

Filters is one tricky part when comes CAML. CAML can easily be generated using tools such as

* CAML Viewer [Links]
* CAML builder [Links]

CAML generated by these tools include "Query" and "Where" XML element tags, which in my opinion makes perfect sense. As it turns out these tags do not play well when passed in to alert.Filters properties. Remove these tags and pass the inner content and it works like a charm.
Take a look at the code below.

alert.Filter = "<Eq><FieldRef Name=\"ContentType\"/><Value type=\"string\">" + "Item" + "</Value></Eq>";

What we are doing here is applying filters on Field Type "ContentType" having value "Item".

Code Dump
[Code]
SPSite site = null;
SPWeb web = null;
try
{
site = new SPSite("http://server/");
web = site.RootWeb;
web.AllowUnsafeUpdates = true;
SPList list = web.Lists["TestList"];
foreach (SPUser user in web.SiteUsers)
{
if (user.Name.ToUpper().Contains("user name"))
{
SPAlert alert = user.Alerts.Add();
alert.Filter = "<Eq><FieldRef Name=\"ContentType\"/><Value type=\"string\">" + "Item" + "</Value></Eq>";
alert.Title = "My Alert";
alert.AlertType = SPAlertType.List;
alert.EventType = SPEventType.All;
alert.List = list;
alert.AlertFrequency = SPAlertFrequency.Immediate;
alert.AlwaysNotify = true;
alert.Update(true);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine("================");
Console.WriteLine(ex.Source);
Console.WriteLine("================");
Console.WriteLine(ex.StackTrace);
}
finally
{
if (site != null)
site.Dispose();
if (web != null)
web.Dispose();
}
[/Code]

Make sure you dispose of site & web objects, if not a heavy penatly will be applied on memory usage.
Alternatively, if you are using SPContext to get site and web object do not dispose then

Hope this helps.

Cheers

4 comments:

Saurabh said...

Hi Sandeep......

Nice article
one thing i want to know.
how can we add multiple users to the alert.
if i have 2000+ users then foreach is not a good option to add alerts to the users.

Any Ideas?

Kind Regards,
Saurabh

Sandeep said...

use CAML instead of for each!!

Saurabh said...

I have no Idea about this,
How can we do this???

Kind Regards,
Saurabh

Anonymous said...

Sandeep nice article!!
But I have one question.. will it be possible to establish an email alert for the entire site by using alert.AlertType = SPAlertType.Custom; ? If this cannot be done, is there any way to establish email alerts for entire site?

Thanks