This blog is discontinued

Having realized that I need  more control of the content and the  customization options in order to to get my blog to the next level,  I have decided to close this one down. My new blog is already up and running on www.sharepointviking.com . I will keep this one alive for a while in read mode , to support those who use the 70-480 Study Guide in their exam preparations. The study guide is discontinued in my new blog, but the links are still there, taking you to this site.

 

Best Regards

 

The SharePoint Viking

Additional SharePoint 2013 MCSD Certification info revealed

Hi All!

To follow up Vlad Catrinescu’s  recent shout outs on the new info/rumours concerning the SharePoint 2013 MCSD Certification, here are the topics that most probably will be covered in the 70-488  and 70-489 exams. Up till now only the exam numbers have been publicized, so please note the new names as well:

70-488:  Developing Microsoft SharePoint Server 2013 Core Solutions

Planning and Designing SharePoint Sites

- Implementing Authorization and Authentication

- Accessing and Managing Data

- Implementing  SharePoint Solutions

- Implementing User Experience and Information Architecture

- Creating Business Processes

- Creating Office Apps

70-489:  Developing Microsoft SharePoint Server 2013 Advanced Solutions

-Managing SharePoint Solutions, BI, and Systems Integration Designing and Implementing Search

-Implementing Managed Metadata Service (MMS)

-Implementing  BCS

-Implementing User Profiles and Customizing Social Workload

-Implementing ECM and WCM

-Performance and Troubleshooting

We already know that the other 2 exams that sum up the 2013 MCSD certification are 70-480 Programming in HTML 5 with JavaScript and CSS3, and 70-486 Developing ASP.NET MVC 4 Web Applications. So to the aspiring candidates: there’s no need to wait for the SharePoint specific ones, because you need a considerable amount of time to prepare for these 2 as well: For the 70-480, please feel free to try out my own study guide here.

Happy New SharePoint Year !!

I’d like to wish each and every SharePointeer around the world a Happy and Successful New Year!!  Why shouldn’t you believe so since you are working with such a great tool (ok, not tool… a great platform )!!

I have lots of plans for the year to come and I know the first 6 months will become extremely busy so I have already booked the necessary vacations .  The most thrilling part will be starting up in my new job from March at Skill ( www.skill.no ). This is a small but highly dynamic consulting house that are filled with great people that are highly skilled in most of Microsoft’s server technologies and I expect to both boost my own competence to a new level + I also intend to give a lot back. 60 days left and counting…

But there is more, because I don’t intend to sit back and rest much during in my spare time, especially not before summer. I have always dreamt about becoming an author, so why don’t mix that wish with SharePoint?  If everything goes well, my  first book “Pro SharePoint 2013 Workflows” (title might be changed) will be available from Amazon and other online stores by the end of August, and I have already had a couple of late nights working with the first draft to be delivered to my publisher in a couple of weeks time.  Tough work, but a great experience and the learning curve is steeper than you can ever imagine!

I’m also pushing forward to organize and arrange the first ever SharePoint Saturday event in Norway, hopefully before the summer vacation takes over. I love the SPS concept and I think it’s a great way to increase the interest for SharePoint in our local area,  but also to increase the overall activity among the local user groups members. We have gathered a small group of motivated organizers, so I’m quite sure this will be a success. When things hopefully start to materialize, we will make sure the necessary information will be spread out through the usual channels.

I have also been pretty outspoken in my ambitions to work towards getting the SharePoint 2013 MCSM certification, so I’m planning to take  quite a number of exams  this year.  You’ll never  learn  about all  bits and pieces of SharePoint but the Master cert.  is probably the closest  you can get.

Last but not least, I’m hoping too meet and socialize with as many fellow SharePointers as possible. I  tweeted,  chatted and mailed with hundreds of them last year, but sadly, I have only had the opportunity to meet only a few of you in person so far.  My plane is  to do something with  that , so expect to see me at  a lot more SharePoint events this year. Until then, keep up the great work that you all do for the Wordwide SharePoint Community (from now on WSC)

Kind Regards

Bjoern H Rapp – The SharePoint Viking

CU_Viking_War_Helmet

 

 

A SharePoint 2013 Bing Maps App – Part 3, using the GeoLocation API to mark the user’s current position


Part 1

Part 2

In Part 1 and 2, I did the bulk part of this Bing Map demo series,  so onwards I will concentrate on adding smaller pieces of functionality. Today I’m going to demonstrate how to use the GeoLocation API to plot your current position, and in the next upcoming part we will use a SharePoint list to track your whereabouts each time you open the map application and plot your movements on the map.

The GeoLocation API is part of HTML5 and is used to get the geographical position of a user. Since this can compromise user privay, the user is asked to confirm permission to report location information.   html5rocks.com (my favourite html5 site!) has a nice tutorial that discusses the basics of  the GeoLocation API.

To use the API to plot our current position when the app launches, we need to do some changes to the LoadMap function we created previously in the App.js file in our App project. Open the file and edit the function as follows

function LoadMap() 
{
   // Use the Geolocation API to determine your current location
   var startPos;
   navigator.geolocation.getCurrentPosition(function (position)
   {
      startPos = position;
      var location = new Microsoft.Maps.Location(startPos.coords.latitude, 
                     startPos.coords.longitude);
      var mapType = Microsoft.Maps.MapTypeId.road;
      creds = "<your Bing Maps Account Code>";
      map = new Microsoft.Maps.Map(document.getElementById("mapDiv"),
      {
         credentials: creds,
         center: location,
         mapTypeId: mapType,
         zoom: 7
      });
      var pushpin = new Microsoft.Maps.Pushpin(location);
      map.entities.push(pushpin);
   });
} 

The GeoLocation API is published through a geolocation child object as part of the navigator object. The call to getCurrentPosition() initiates an asynchronous request to detect the user’s position, and queries the positioning provider (GPS, wifi etc.) to get the information. Most of the original code in LoadMap() has been wrapped into the callback function. There, the JSON response from getCurrentPosition() is parsed into latitude and longitude postitions. These are in turn used as parameters in the call to the Bing Maps Ajax function Microsoft.Maps.Location() to return the location to be displayed on the map.

The 2 last lines of the updated function creates a pushpin that marks the position on the map.

Redeploy the app , launch it, and if everything went well, your current position will be in the center of the map .

Exam 70-480 Programming with HTML5, Javascript and CSS3 Study Guide

If you plan to study for the Programming HTML5 with Javascript and CSS3 70-480 exam, but you don’t want to wait for the  proper study materials to arrive next year, or you don’t want to take or can’t afford a classroom training course, you have to prepare yourself for lots of work browsing the web for resources and information that cover the list of skills that will be measured . In the beginning I just created a list of links in my browser favourites folder , but decided afterwards to create a proper reference that I have continuosly been working on, and now I feel it’s good enough to share it with the community.  This guide is free to use for everyone, but it certainly has potential for improvement , so comments on eg. links to better resources on certain topics or anyhing else that might be helpful are most welcome.

The guide’s structure is in accordance with the “Skills Measured” section on the exam’s home page at Microsoft Learning.


Implement and Manipulate Document Structures and Objects(24%)

Create the document structure

Structure the UI by using semantic markup
Create a layout container in HTML

Write code that interacts with UI controls

Programmatically add and modify HTML elements
Implement media controls (audio and video)
Implement HTML Canvas and SVG Graphics

Apply styling to HTML elements programmatically

Change the location of an element
Apply a transform
Show and Hide elements

Implement HTML5 API’s

Implement App Cache API
Implement Storage API
Implement GeoLocation API

Establish the scope of objects and variables

Define the lifetime of variables
Keep objects out of the normal namespace
Use the “this” keyword to reference an object that fired an event
Scope variables locally and globally

Create and implement objects and methods

Implement native objects
Create custom objects and custom properties for native objects using prototypes and functions
Inherit from an object
Implement native methods and  create custom methods


Implement Program Flow (25%)

Implement program flow

Iterate across collections and array items
Manage program decisions by using switch statements, if/else and operators
Evaluate expressions

Raise and handle an event

Handle common events exposed by DOM(OnBlur, OnFocus, OnClick)
Declare and handle bubbled events
Handling an event by using an anonymous function

Implement exception handling

Set and respond to error codes
Throw an exception
Request for null checks
Implement try-catch-finally blocks

Implement a callback

Receive messages from the HTML5 WebSocket API
Use jQuery to make an AJAX call
Wire up an event
Implement a callback by using anonymous functions
Handle the “this” pointer

Create a web worker process

Start and stop a web worker
Pass data to a web worker
Configure timeouts and intervals on the web worker
Register an event listener for the web worker
Limitations of a web worker


Access and Secure Data (26%)

Validate user input by using HTML5 elements

Choose the appropriate controls based on requirements
Implement HTML input types and content attributes (for example, required) to collect user input

Validate user input by using JavaScript

Evaluate a regular expression to validate the input format
Validate that you are getting right kind of data type by using built-in functions
Prevent code injection

Consume data

Consume JSON and XML data
Retrieve data by using web services
Load data or get data from other sources by using XMLHTTPRequest

Serialize, deserialize and transmit data

Binary data
Text data (JSON, XML)
Implement the jQuery serialize method
Form.Submit
Parse data
Send data by using XMLHTTPRequest
Sanitize input by using URI/Form encoding


Use CSS3 in Applications (25%)

Style HTML text properties

Apply styles to text appearance(color, bold, italics)
Apply styles to text font (WOFF and @font-face, size)
Apply styles to text alignment, spacing and indentation
Apply styles to text hyphenation
Apply styles for a text drop shadow

Style HTML box properties

Apply styles to alter appearance attributes (size, border and rounding corners, outline, padding, margin)
Apply styles to alter graphic effects(transparency, opacity, background image, gradients, shadow, clipping)
Apply styles to establish and change an element’s position (static, relative, absolute, fixed)

Create a flexible content layout

Implement a layout using a flexible box model
Implement a layout using multi-column
Implement a layout using position floating and exclusions
Implement a layout using grid alignment
Implement a layout using regions, grouping and nesting

Create an animated and adaptive UI

Animate objects by applying CSS transitions
Apply 3D and 2D transformations
Adjust UI based on media queries(device adaptations for output formats, displays, and representations)
Hide or Disable controls

Find elements by using CSS selectors and jQuery

Choose the correct selector to reference an element
Define element, style and attribute selectors
Find elements by using pseudo-elements and pseudo-classes (for example, :before, :first-line :first-letter, :target, :lang, :checked, :first-child)

Structure a CSS file by using selectors

Reference elements correctly
Implement inheritance
Override inheritance by using !important
Style an element based on pseudo-elements and pseudo-classes (for example, :before, :first-line :first-letter, :target, :lang, :checked, :first-child)


OTHER RESOURCES

Videos

Developing HTML5 Apps Jump Start
CSS Tutorial for Beginners
Getting offline with AppCache
HTML5 offline and local Storage

Code Resources and Samples

CodeShow

Books

70-480 Exam Ref ( will be available in April 2013)
The Definitive Guide to HTML5
The Book of CSS3
Javascript – The Complete Reference
Programming Windows 8 Apps with HTML, CSS and Javascript ( Free e-book)

Other Resources

CodeFoster – Jeremy Foster’s Blog
Michael Palermo’s Blog
HTML5 Rocks
Javascript Reference from Mozilla
jQuery home page
HTML5Code
CSS3.com
CSS3 Explained
JavaScript Tutorial
Document Object Model

A SharePoint 2013 Bing Maps App – Part 2


Part1 

Part3

In Part 1 we created a fully interactive Bing Map into  a SharePoint-hosted app and deployed it to the host web. Now it’s time to explore some of the capabilities with Bing Maps and use them together with data stored in SharePoint.

Location Search

An interactive map without a location search interface, is a sad map. The Bing Maps Ajax control does not have this functionality itself, but you can easily implement it to your application by using the Bing Map REST Services.

In this demo we are going to create a simple search functionality, where the user enters a geolocation, then the input data will be passed to the Bing service . If found, the service  returns the position to the map which changes  its view to put the location in the center.

The first thing we will do is to create a text field and a button for the user to enter and submit searches.  Open up the default.aspx file in the project  we created in part 1.  Add the following code after the <div id=”mapDiv”> tag:

snip5

Next, add the  controls style class and update the map style class in the App.css file as follows:

snip6

Open up App.js and define the following global variables at the top of the file:

snip7

Add the Search button onclick event handler function to App.js:

snip8

The map.getCredentials() call requires some explanation. The key thing is that Bing REST Services also require the Bing Maps key, so this function call is used to retrieve the key from the map object to make sure the Maps and the Service are running in the same session. The requestLocation  parameter is a callback function which is called after the getCredentials() function has completed.

To support the functionality above, we have to do some changes to the LoadMap function we created in the first part. Edit it to look as follows:

snip9

Next, add the requestLocation() callback function:

snip10

First we build the geocode request to the Bing Maps REST Services using the value entered by the user. The service can return the response as either an XML or a JSON object. For javascript , JSON is usually the best choice, so the output argument is set to json. With JSON you also need to provide a callback function to the jsonp parameter. Finally set the key parameter to your Bing Maps key .

The other section of the function appends a <script></script> tag to the body element, setting the source to the loc  REST service call string we just created.

What remains to be done is to add the locationCallback() function which is invoked when the REST service call returns. This function will first test and validate the return location string, then it will use the boundary data in the location string to define and update the map view’s boundaries, resulting in the found location being centered on the map. Finally we grab the coordinates and add a pin to mark the location

snip11

Build and deploy your project, then open SharePoint and launch the app. Enter a location in the input box below the map and press Search. If everything goes well, the requested location is found by the service and centered onto the map. Try experimenting with different locations, like rivers, buildings, addresses etc.

snip4

Interfacing with the Host web.

Now it’s time to add some SharePoint-ness to the project. We are going to load a set of locations from a list in the SharePoint host into the map. So go ahead create a new custom List, name it Locations, and optionally add other columns to add some simple metadata to the locations. My list looks like this (the last item is the address of one of  Google’s offices in Austin, Texas):

snip12

There are lots of other sites and blogs describing how a SharePoint app interacts with the SharePoint host so I won’t go into those details here. My favourite resource is of course Microsoft themselves, so if you want to dig into the details, here’s a good starting point: http://msdn.microsoft.com/en-us/library/jj163230.aspx

By default an app does not have permissions to access resources on the host. To be able to do that you must define your permissions requests in the app manifest. For this exercise we just need read access to lists so open the AppManifest.xml file in the project. In the Permission Requests section, click inside the Scope column and select Web and in the Permission column, select Read . Add another Read permission for the List scope.

snip13

Now, open default.aspx and add a new button under the Search button definition as follows:

<input type=”button” value=”Mark locations from list” onclick=”getLocationsFromList()” />

Due to a possible bug when using SPHostUrl ( explained in a blog post by Chris O’Brien ), we need to preserve the SPHostUrl and SPAppWebUrl parameters during load. These  are provided to the app during launch from the host site via the query string and hold the host web and the app web url respectively. First let’s add a  function that parses the querystring:

snip15

Also add 2 global variables, hostWebUrl and appWebUrl to the top of the list. Then add the 2 following lines at the beginning of the sharePointReady() function:

snip16

Next,  add the getLocationsFromList() event handler in App.js:

snip17

This function uses CSOM to read the contents from the Locations list, using a CAML query to filter  the Title field.

Before adding the callback functions, add a global variable named allItems at the top of the file .

Then add the 2 callbacks invoked from executeQueryAsync() .

snip19

The success() function reads each Title field and calls getLocations() . This function in turn calls requestLocations() in order to request the locations from the Bing REST Service. These 2 functions are more or less identical to the requestLocation() and getLocation() functions defined previously. The only difference is requestLocations() taking a list item field as input. A potential reusability here, but I haven’t put much focus on it,  so I leave that part as an exercise for the reader. The 2  functions are defined as follows:

snip20

As you can see the same locationCallback function is used in requestLocations() to pin the locations to the map.

Finally add another global variable named  locations to the top of the file to hold the location names.

Rebuild and deploy the app. Launch it on your SharePoint test site and press the Mark locations from List button . Then zoom out the map and verify that all the locations defined in the list have got pushpins in the correct positions on the map.

That was all for now;  I hope some of you have found this interesting. In Part 3 we will be looking at getting route directions between 2 points defined in a list, and we will use the response information provided by the service to update other fields in the same list.

SharePoint 2013 MCSD Certification

A few weeks ago  I wrote a blog post about the opportunity to take the 70-480 HTML5 Programming with Javascript and CSS3 at no charge during a period that lasts until 31.03 2013.  In the same post  I also indicated the  possibility that the exam could become a part of the not yet released SharePoint 2013 MSCD Certfication

Yesterday during the Microsoft Events presentation on the SharePoint  2013 MCSM program, Microsoft themselves confirmed that 70-480 indeed will be part of the new SharePoint MCSD program. Some additional info was also revealed. The certification will consist  of 4 different exams.  2 are  SharePoint 2013 development oriented while the other 2 are more generic  web development exams.   70-480 will be one of the web developer exams.

The other web developer exam is still TBD but since 70-480 is HTML5 and Javascript oriented, I’m pretty sure the other one will have more focus on  C#/VB-development, possibly including  ASP .NET MVC 4 , WebForms or even Windows Store Apps parts. Hopefully we’ll find out soon. .

The SharePoint Developer exam parts have got their id’s assigned  ( 70-488 and 70-489) but no further information is currently available.

So for those who can’t wait to take on 2013 MCSD  (and that includes myself), start preparing for 70-480 now!!

A SharePoint 2013 Bing Maps App – Part 1

Part 2
Part3

I have always been fascinated with maps, GPS’es and other navigational stuff. So why don’t try to mix this with SharePoint!!   In a series of posts I’m going to build a SharePoint 2013 app using Bing Maps API, demonstrating simple map loading, adding entities, location searches and getting route directions. I will also demonstrate some interactions between lists in the SharePoint Host Web and the app itself, residing in the app web.

Create a Bing Map Account

If you want to use Bing Maps in  your applications, whether it is a Windows 8 app, phone app, or standard web application, you need a Bing Maps account key. This can be obtained at the Bing Maps Portal here. NB, you need a Windows Live ID to register for the account. When you have completed the registration, login to the Bing Maps Portal site and  click Create or view keys in the left navigation menu. Fill out the Create Key form and click Submit. For this exercise I’m going to use the following entries:

Application Name:   Bing Map Demo
Application URL:     <url to your SharePoint 2013 or Office 365 dev site>
Key Type:                Trial   ( valid for 90 days)
Application Type:    Private Website.

Copy and save the generated key from the list below the form.  You will need it later on.

Microsoft provide several Bing Maps API options for developers, depending on the target platform and whether you want a static or interactive map. The differences and suggested use cases are outlined here. For this demo I’m going to use the Bing Maps Ajax Control, Version 7.

Create the project

With the account key in place, it’s time to start with some coding:

Open VS 2012 and create a new   App for SharePoint 2013 project . Give it an appropriate name, eg. BingMapAjaxDemo and click OK.  In the New App for SharePoint  dialog, enter and validate your SharePoint site where you will install the app. Select SharePoint-hosted in the drop down menu and click Finish .

Microsoft recommend using utf-8 encoding on the Bing Maps host page, so to support that we need to add a couple of lines in the <head> section.
Open default.aspx from Solution Explorer and locate the <asp:Content>  tag named PlaceHolderAdditionalPageHead. Enter the following 2 lines at the top of the section, above the first <script> tag:

<meta http-equiv=”content-type” content=”text/html; charset=”utf-8″ />
<script charset=”utf-8″ type=”text/javascript” src=http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0 />

The first line adds the charset to the http header while the second one loads the Bing Maps API using the same charset.

Remove the default contents inside the PlaceHolderMain tag, and add the following code which will create a div area to hold the map:

<body onload=”LoadMap();”>
   <div id=”mapDiv” class=”map”></div>
</body>

Next, add this class style description into the  the App.css file:

.map {
     position: absolute;
     top: 20;
     left: 10;
     width: 600px;
     height: 600px;
     border: #555555 2px solid;
}

Finally, add the following map loading function into the App.js file. This method will be invoked by the main page onload event:

function LoadMap() {
     var map = Microsoft.Maps.Map(document.getElementById("mapDiv"),
    { credentials: "<your Bing account key here>"});
}

Deploy and Run the App

Right-click the solution file and select Deploy.  When completed,  open your SharePoint site and click on the BingMapsDemo link in the “Apps for testing…” list  to start the app. When the page is opened it will look like this:

Out of the box you have lots of functionality readily available. You can zoom the map, change map type and pan the map in all directions. Now let’s say you want to load the map at a specific location using a custom zoom level, and you want the Road map type to be the default map. Just edit the LoadMap() function to make it look as follows:

function LoadMap() {
   var loc = new Microsoft.Maps.Location(36.1,-115.1); // your favorite conference city
   var mapType = Microsoft.Maps.MapTypeId.road;
   var map = new Microsoft.Maps.Map(document.getElementById("mapDiv"),
     credentials: "<your account code>",

     center: location,
     mapTypeId: mapType,
     zoom: 7
   });
}

When you redeploy and relaunch the app, the map will now look like this:

Up to this point we have concentrated on adding functionality to just load the map when the app is launched, but there are lots of more cool stuff to do, like searching and getting route directions, and we haven’t done any direct interaction with the host web using SharePoint API’s  yet. That will be the topic of Part 2 of this demo.

NB! If you try to debug the app directly from VS by pressing F5, you will probably get a javascript error message saying “Microsoft is undefined”. Cool message, but I haven’t yet been able to find the exact cause. If you press continue you will still be able to launch the app without errors. So if anyone has any clue why this is happening , please don’t hesitate to post a comment!

How to send alerts to a group in SharePoint 2010

A few days ago I wrote a blog post on how to create a Timer Job that monitored a document library and notified a group of subscribers on any changes by sending a daily summary by e-mail, more or less mimicking a Document Library alert notification to groups.  This time I will show you how to send alerts to groups OOTB.

Creating alerts in SharePoint to receive change notifications by mails when list  and library items are created or changed,  is a common task well known to many users, but normally you can only create an alert to yourself.  What if you want to send alerts to notify a group of users instead?  Adding more users into the input box will only work until you reach the 256 character limit.  That’s not very useful if you want to add,  let’s say 200 users.

To achieve your goal you have to configure a new or existing group in AD as a “Security” group type.   You also have to mail-enable the group in Exchange .     These tasks are routinely performed by the IT staff with domain admin privileges, but anyway,   here’s a howto:

Active Directory

Open the Active Directory UI

1) In the left treeview: Click the OU node where you want to create the group in, then select New->Group in the popup menu.

2) In the New Object – Group dialog, enter a Group name in the upper text box, set the Group Scope to “Universal” and  the Group Type to “Security”. Click OK

3) Double click on the new group and select the Members tab to add members…  Close Active Directory when finished.

Exchange

To mail-enable the group, open the Exchange 2010 Management Console

1) In the action pane, expand Recipient Configuration , and then click Distribution Group .

2) In the action pane, click New Distribution Group

3) Click Existing Group on the Introduction page and then click Browse

4) In the Select Group dialog box, select your newly created group and then click OK , then click Next .

5) On the Group Information page, modify the Display Name and Alias    fields as required (both are set to the group name by default) , when finished click Next.

6) On the New Distribution Group page, review the summary and then click New.

7) If the group was successfully created, click Finish

Tasks 1-7 above can also be perfomed by running the following cmdlet in the Exchange Management shell:

Enable-DistributionGroup -Identity  “<yourgroupname>”;

SharePoint

With the group properly set up,  open SharePoint, select your library and create a new alert by clicking the “Alert Me->Set Alert on this library” drop down button on the ribbon.

In the New Alert form you should now be able to use the People Picker in the “Send Alerts To” field  to add your newly created group. You need Full Control access on the parent site to do this . A standard user can, as already mentioned,  add himself only.

A SharePoint 2010 Timer Job example with e-mail notification

I have from time to time seen requests for code samples using Timer Jobs in SharePoint 2010 (yes, not everyone has switched to 2013 yet!)  together with e-mail notification  in order to send reports from the job to recipients. A couple of months a go I did a project which monitored changes to doc libraries on a given site. To be specific,  I monitored changes to the Modified fields in the libraries.  I made it into a Timer Job that ran daily at 17.00 PM , checked if there had been any changes, and then created a simple report on the changes as a mail message to a list of subscribers. For the e-mail interface I used the System.Net.Mail library. Here’s a walkthrough of how I built the solution:

Create Project

Open Visual Studio 2010, create a new SharePoint 2010 Empty Project and give it an appropriate name,  eg.  “MonitorChanges”. Specify a SharePoint site for the deployment and set the project to deploy as  a Farm Solution.

Next, in Solution Explorer, richt click “Features” and then “Add Feature”.  Right click the new Feature1 node and rename it to “MonitorChangesFeature”.  The solution should now look like this:

Double-click the MonitoreChangesFeature node to open the Feature Designer. Set title to “MonitorChanges”, add some text in the Description field, and set scope to “WebApplication”.

Set the Job Schedule

To set up the timer schedule for the job when it’s deployed to the farm, we are going to use an event receiver. In Solution Explorer, right-click the MonitorChangesFeature node and then select “Add Event Receiver”.

Open up the newly created .cs file, uncomment the FeatureActivated and FeatureDeactivating events, and remove the remaining commented code lines.  Add the following code to the FeatureActivated event:

The code checks for existing instances of the job and deletes them if there are any. Our job is associated with a web application so we have to cast the parent feature accordingly in order to get a reference to the running job. Next it creates an instance to an SPJobDefinition-derived class (which we will create shortly).  I then use an SPDailySchedule  object to set up the job to run on a daily basis starting at 17.00 PM . Finally I assign it to the job’s Schedule property and call its Update() method.

Add the code below to the FeatureDeactivating event to make sure any instances of the job are deleted when the feature is deactivated:

Create SPJobDefinition-derived class

With the scheduling functionality in place, it’s time to add the job functionality itself.  Add a new class to the project  ( in Solution Explorer, right-click project name , then “Add New Item->Class”).  Name the file MonitorChanges and click “Add” . Open the file and add 2 using statements for Microsoft.SharePoint and Microsoft.SharePoint.Administration.

Set the MonitorChanges class to inherit from SPJobDefinition. Then add the following 3 constructors:

The last constructor is the one being invoked from the FeatureActivated event. As you can see I have set the SPJobLockType enum to Job, which forces the job to run on only one machine in the farm ( I only have one machine in mine, so setting SPJobLockType to None would probably have same effect).

In order to make the job  run,  you have to override the Execute() method of the SPJobDefinition class. Add the following code below the constructors:

To ensure that the job has full control rights, I run the code inside a RunWithElevatedPrivileges block. This may not always be necessary, so depending on the type of task to be executed, the block can be removed. Then set the url in the SPSite constructor to point to the site you specified during the creation of the project.

I want to check for changes in all document libraries in all the subsites under the current site. To achieve that goal I use a SPSiteDataQuery object with the Webs property  set to the Recursive scope and Lists set to 101.  The query returns the Title field from all documents with changes in the Modified field during the last 24 hours.  The results are put in a DataTable object ( you may have to add another using statement for System.Data).  Then the titles are read into a local List object.

Add the E-Mail functionality

With a list of changed document titles available, it’s time to add the code that creates and sends the mail message  with the data to the subscribers. To keep things simple, the subscribers are stored in a default custom list on the site where the e-mail addresses are located in the Title field.

Add the e-mail helper method below to the MonitorChanges class ( you may have to add a using statement for System.Net.Mail):

The SPWebApplication.OutBoundMailServiceInstance.Server.Name property contains the registered mail server name from the farm settings (found in Central Admin->System Settings->Configure outbound e-mail settings->Outbound SMTP Server ) .  The rest of the code composes the mail header and body into a message listing the changed document names. I also use a couple of helper methods to get the e-mail addresses from the subscribers list to populate the MailMessage.To property and to create the mail body:

Finally,  add a call to MailChangesToSubscribers() at the end of the Execute() method (after the for (int i…) loop):

Build and deploy the project.  If everything went well, your timer job should now be listed along with the  others on the scheduled jobs page .  Open Central Admin->Monitoring->Review Job Definitions and verify that the MonitorChanges  job is listed. Double-click the title to open the Edit Timer Job page and verify that the job is set to run daily at 17 PM.

To test it, create the Subscribers list as a default list on the test site, and add a new item with your mail address in the Title field.  Add a document to the Shared Documents library or edit an existing one, and verify that you receive a mail after 17 PM,  containing the new document title in the mail body. Then try changing several documents in different libraries and run another job test.

Happy coding , and I hope you won’t become too annoyed by my obsession with black code editor backgrounds !