By: Robert Christ
Event Receivers, Timer Jobs, and Workflows.
Of the available ways to add business logic into the SharePoint environment, these three options are truly the developer’s workhorses.
Logging from Any Location
No matter what type of code you are writing, it is always a good idea to log your output to the SharePoint 2010 trace logs. In SharePoint 2010, this is exceedingly simple.
Simply provide the category name, and choose the remaining enums to best fit the log.
SPDiagnosticsService.Local.WriteTrace(0, new
SPDiagnosticsCategory(“My category”,
TraceSeverity.Unexpected, EventSeverity.Error),
TraceSeverity.Unexpected, ex.Message, ex.StackTrace);
Workflows
Unfortunately, of the three, only the workflow comes prepackaged with a feedback system for the user.
When a SharePoint user or administrator adds a workflow to a list or library, SharePoint automatically adds a new column that reflects that workflow’s status.
Into this column, it is quite easy to give the SharePoint user feedback. To make this easy and reuseable, I use a series of extension methods such as the following.
public static class ExtensionMethods{
/// <summary>
/// Records an Exception to the Workflow History List as a
/// <see cref="SPWorkflowHistoryEventType.WorkflowError"/>.
/// </summary>
///
/// <param name="prop">This <see
/// cref="SPWorkflowActivationProperties"/>
/// object instance.
/// </param>
///
/// <param name="ex">The Exception to record.</param>
public static void RecordException(this
SPWorkflowActivationProperties prop, Exception ex) {
prop.Workflow.CreateHistoryEvent(
(int)SPWorkflowHistoryEventType.WorkflowError,
0, prop.OriginatorUser, "Error",
ExtensionMethodMessages.FormatException(ex),
String.Empty);
}
}
public static class ExtensionMethodMessages{
public static string FormatException(Exception ex) {
if (ex != null) {
return "Exception: " + ex.GetType().Name +
Environment.NewLine + "Message: " + ex.Message +
Environment.NewLine + "Stack Trace: " + ex.StackTrace;
}
else {
return string.Empty;
}
}
}
With the above code, it is now as easy as typing prop.RecordException(ex), and when the user clicks the “In Progress” link shown below, they will be able to read the error.
With a little Google searching, it is also quite easy to manually control text within the workflow status column itself, so with these two tools, the user should be able to always directly understand what is occurring within the workflow.

Item Event Receivers
Unlike SharePoint workflows, item event receivers have no explicit manner of logging for the SharePoint user. As such, we must invent one.
We could recreate the same user feel as is done for workflows. This would mean we log to a workflow history list, and create a column on our event receiver list which we manipulate to show status messages. This status column would be a hyperlink column, and would redirect to an aspx page, which would include a web part which showed a filtered view of the workflow history list.
However, I find that in many of my solutions, the following is sufficient.
Simply create a new “Status” column on the list on which the event receiver is running, and update this column with the message. Then, logging to the status column is as simple as:
object lockingObject = new object();
/// <summary>
/// An item was updated
/// </summary>
public override void ItemUpdated(SPItemEventProperties
properties){
//so we don't lose any requests due to concurrency.
lock (lockingObject) {
try {
//So we can call item.Update() without spawning other event
//receiver instances.
this.EventFiringEnabled = false;
RunApplication(properties);
}
catch (Exception ex) {
web.AllowUnsafeUpdates = true;
properties.ListItem["Status"] = ex.Message + " " +
ex.StackTrace;
properties.ListItem.Update(); // Or afterproperties, etc
}
finally {
properties.web.AllowUnsafeUpdates = false;
this.EventFiringEnabled = true;
}
}
Timer Jobs
Unlike item level event receivers and workflows, due to their nature, timer jobs are rarely a standard creature. As such, logging for them is almost always going to depend on the context of the timer job. Always be sure to log to the SharePoint trace logs. Additionally, it is usually also a good idea to log to an “Errors List” or “Status” column, either of which is easily accessible to a SharePoint administrator. Good luck!
By: Robert Christ