Using event receivers you can hook into several predefined SharePoint site/web/list etc. events, get access to event information and run custom code when one occurs.
There’s a basic walkthrough with lots of useful information on MSDN, be sure to check it out.
I wouldn’t list all possible events and sources of events here, the URL above does a nice job in that. Basically you can create an event receiver by subclassing the appropriate class and overriding the self-explanatory virtual methods it provides. There are five classes you can use:
- SPWebEventReceiver: provides events for SPSites and SPWebs.
- SPListEventReceiver: events for SPLists and SPFields, basically to the schema.
- SPItemEventReceiver: events for SPListItems, to the data.
- SPEmailEventReceiver: one event for e-mail enabled lists and webs..
- SPWorkflowEventReceiver: events for workflows.
Most implementations have two types of events: before and after events. This resembles Windows Forms or WPF programming, where you had Clicking and Clicked events. Before events occurs before the event takes place (before SharePoint updates the content database), run on the same thread as the event itself, and provides cancellation and access to the event data. You can access almost every piece of information that will be stored in the After property of the SPItemEventProperties class, except the new item’s (if any) id, which hasn’t been generated yet at this point.
After events lets you run your code after a specific event occurred. By default they run on a background thread, and there aren’t any guarantees that they’ll be runned by the time your page posts back to you. You can control this behavior by setting the synchronization state of your event receiver to synchronous. Then after events will run on the same thread as the event itself.
It’s easy to trigger a stack overflow with event receivers. Imagine that you’ve subscribed to the updating of an SPListItem, and set a property on the same list item from your event receiver. This’ll cause to recursively call the receiver again, until you run out of stack space. To prevent this, there’s a protected property called EventFiringEnabled. Just set it to false, and to true after you’re done. Note that this works only in your own event receiver subclass, not from the outside.
The before events are appropriate candidates for validation. And, if validation fails, you’ll definitely like to cancel further processing of the event. Event receivers provide a way for that. First, you’d like to set the Status of the SPItemEventProperties class to one of the values that indicates cancellation. This by itself won’t cancel the event, after you’ve done this you’ll need to set the Cancel property of this class to true. You can also provide an error message or redirect to another URL using the same class.
SharePoint Timer Jobs are processes that run periodically in the background, managed by the SharePoint ecosystem. Long-running operations you normally would like to run nightly (or any time of the day which is considered off-peak) are ideal candidates to be implemented in timer jobs.
To create and run timer jobs you need two things:
- A class that inherits from the SPJobDefinition base class.
- A feature to deploy your job.
All timer jobs have to inherit from SPJobDefinition. Depending on what you develop there are two constructors you can call. If you’re developing a service application then you must call the constructor which has an SPService parameter, otherwise you’d call the one with an SPWebApplication parameter. You’ll also have to write a parameterless constructor, for serializing purposes. Here’s a list of SPJobDefinition constructor parameters:
- Name: the name of your timer job, must be unique per web application / service.
- SPWebApplication/SPService: the web or service application to associate the timer job.
- SPServer: optionally you can associate your timer job with a SharePoint server, but it’s not a requirement.
- SPJobLockType: the lock type of the job.
There are three lock types for a timer job:
- None: runs the job on all servers on the farm, where the parent web or service application is provisioned.
- ContentDatabase: runs the job once per content database. If you specify this lock level you’ll get the identifier of the current content database in the job’s Execute method.
- Job: the job will run only one time.
After identifying and calling the appropriate constructor, you need to override one method to actually do something. This is the Execute method. If you specified the lock type ContentDatabase, then the guid parameter of this method will contain the current content database’s id. Otherwise you can disregard this parameter. In the execute method you can do anything that needs to be done in your job.
To deploy your timer job you’ll need a feature with an event receiver. In the event receiver’s FeatureActivated method you’ll call your concrete SPJobDefinition’s constructor, assign an SPSchedule object specifying when to run your job and assign it to the job’s Schedule property. Then you’ll have to call the Update method on the job definition, and you’re good to go.
To debug a timer job you’ll have to attach to the OWSTIMER process from Visual Studio. Then if you don’t want to wait the scheduled start time of your job, you can run the job from Central Administration.
There’s a very thorough guide for writing timer jobs here if you need more details.
SharePoint has a somewhat clumsy object model when it comes to permission management but it’s easy to get used to it.
There are two main classes here, one for entities who have permissions, and one for objects on which they have them. SPPrincipal as its name suggests represents a principal who can be a user or a group. The two respective classes are SPUser and SPGroup. As you might figured it out, a user can be member of zero or more groups. The interesting fact is that groups cannot be nested, so it’s a pretty flat hierarchy.
There’s a base class for all securable objects, which is called SPSecurableObject. It’s a nice entry point for all permission operations, since you can deal with a single class. Now to make things easier securable objects can inherit permissions from their parent. You can check if this is the case using the HasUniqueRoleAssignments property. There are two methods to enable or disable permission inheritance, called BreakRoleInheritance and ResetRoleInheritance. SPSecurableObject has a bunch of useful other methods, for example DoesUserHasPermission which checks for a given permission for the current user.
The more interesting thing is that each securable object has a property called RoleAssignments. This is a collection typed SPRoleAssignmentCollection (fortunately using the magic of the Cast<T>() LINQ method you can easily convert it to IEnumerable<SPRoleAssignment>).
An SPRoleAssigment has two noteworthy properties. The first is called Member, and it refers to the principal (SPPrincipal) who has some permissions on the given object. The second is called RoleDefinitionBindings (another strongly typed collection) which contains role definition information, as members of the class SPRoleDefinitionBinding. To make things more complicated you can access the actual permissions on the given object by reading the SPRoleDefinitionBinding class’s BasePermissions property.
Things gone quite complicated, so let’s review some SharePoint terms. Some systems (like ASP.NET) uses the term role to refer to a collection of users. SharePoint uses the term group for this. The term Role is deprecated in the SharePoint object model. It uses the term RoleDefinition instead. A RoleDefinition is a collection of permissions. You can assign role definitions to individual users and groups. So the last term to deal with is permission. A permission is some kind of right on a securable object, like reading, writing, etc. I hope I made the mess a little bit clearer here.