MVPs for SharePoint 2010: Debugging Techniques for SharePoint Online Applications


Editor’s Note: The following is a guest post by SharePoint Server MVP Corey Roth as part of the MVP Award Program Blog’s “MVPs for SharePoint” series. Corey Roth is a
solutions architect at Stonebridge specializing in SharePoint solutions in the
Oil & Gas Industry.  Corey has recently been awarded the Microsoft MVP
award in SharePoint Server.  He has always focused on rapid adoption of
new Microsoft technologies including SharePoint 2010, Visual Studio 2010, .NET
Framework 4.0, LINQ, and Silverlight. When it comes to SharePoint, he
specializes in ECM, Enterprise Search, and Business Connectivity
Services.  As an active member of the SharePoint community, he often
speaks at user groups, Tech Fests, and SharePoint Saturdays. Corey is a member
of the .NET Mafia (www.dotnetmafia.com)
where he blogs about the latest technology and SharePoint.  Corey is Vice
President of the Tulsa SharePoint Interest Group.  He loves contributing
to the SharePoint community and currently has four active open source projects
on CodePlex.

There is a ton of excitement around SharePoint Online, part
of Microsoft’s Office 365 offering. 
Developing applications in the cloud is really not much different than
developing a sandboxed solution. However, when it comes to debugging, we need
to think outside-of-the-box a little. 
We’ve become a little spoiled by the great new SharePoint developer
tools that came with Visual Studio 2010. 
We can still use those tools, but unfortunately in the cloud we don’t
have the luxury of F5 deployment.  In
today’s article we will discuss some of your options for outputting debugging
information in the cloud.  If you’re
looking for breakpoints, I’m sorry to disappoint you, but hopefully you can
leverage some of these techniques when coding your next SharePoint Online
application.

Start in the Sandbox

If you’re not familiar with developing in the cloud yet, you
might start by taking a look at my article, Office
365 How to: Build and Deploy a Web Part with SharePoint Online
.  This article walks you through step-by-step
how to create a sandboxed solution in Visual Studio 2010 using a local
SharePoint environment and then deploy it in the cloud.  Another good resource is the SharePoint
Online for Office 365: Developer Guide

Some of the debugging techniques demonstrated today are based on
recommendations in this guide.  These
guides should get you quickly started creating applications for SharePoint
Online. 

When it comes to debugging, the best place to start is in
your own local environment.  Obviously
your local environment will never match the cloud exactly, but if you are
deploying dependent items such as content types and lists via feature, you’re
in a good place.  This means you have a
reasonably good chance that your code referencing these items will work both in
the sandbox locally and in the cloud.

For today’s purposes, let’s start with a simple
web part that adds a task to the built-in Tasks list of a Team Site.  Here’s what the code looks like.

using System;

using
System.ComponentModel;

using System.Web;

using System.Web.UI;

using
System.Web.UI.WebControls;

using
System.Web.UI.WebControls.WebParts;

using
Microsoft.SharePoint;

using
Microsoft.SharePoint.WebControls;

 

namespace SharePointOnlineDebugging.CloudDebuggingWebPart

{

    [ToolboxItemAttribute(false)]

    public class CloudDebuggingWebPart : WebPart

    {

   
    private Label TitleLabel;

   
    private TextBox TitleTextBox;

   
    private Button SubmitButton;

 

   
    protected override void CreateChildControls()

   
    {

   
        // add controls to web part

   
        TitleLabel = new Label() { Text = “Enter Task
Title: ” };

   
        TitleTextBox = new TextBox();

   
        SubmitButton = new Button() { Text = “Add” };

 

   
        // attach event handle to click event

   
        SubmitButton.Click += new EventHandler(SubmitButton_Click);

 

   
        Controls.Add(TitleLabel);

   
        Controls.Add(TitleTextBox);

   
        Controls.Add(SubmitButton);

   
    }

 

   
    void SubmitButton_Click(object sender, EventArgs e)

   
    {

   
        using (SPSite siteCollection = new SPSite(SPContext.Current.Site.ID))

   
        {

   
            using (SPWeb site =
siteCollection.OpenWeb(SPContext.Current.Web.ID))

   
            {

   
                SPList tasksList =
site.Lists["Tasks"];

 

   
                SPListItem newItem =
tasksList.Items.Add();

   
               
newItem["Title"] =
TitleTextBox.Text;

 

   
               
newItem.Update();

   
            }

   
        }

   
    }

    }

}

 

The code simply creates a label, textbox, and
button.  When the button is clicked, it
gets a reference to the Tasks list of
the current site and then adds a new item. 
I can first verify that this code works correctly by testing it locally
on my own SharePoint server.  I can debug
it and resolve any issues there before deploying the solution package to
SharePoint Online.  Once you’re happy
with your solution locally, it’s time to send it to the cloud.  Here is what our web part looks like when
deployed to SharePoint Online.

Before we start debugging, let’s take a look and see how
SharePoint Online handles exceptions.  As
an example, let’s produce an exception by specifying the wrong name for the Tasks list.  We’ll use this exception throughout the rest
of the article.

SPList tasksList =
site.Lists["Tasks List"];

 

When we try to insert a task, the reference to
the wrong list in the above code generates an exception and this is what the
user sees.

This is not exactly a useful error message for the user or
the developer.  At this point, we have
absolutely no way to figure out what went wrong.  We can’t even go look in the ULS logs since
we’re in the cloud.  So what do we
do?  We have to go back to more traditional
debugging techniques that some of us used years ago.   We
have to add code to do our debugging. 
This might sound archaic or even insane to some of you, but it’s really
our best way to troubleshoot in the cloud. 
Developers have been using techniques like this for years long before we
even dreamed of breakpoints.  It really
does work pretty well.

To do our debugging, we’ll create a method to
handle the debugging and insert a call to it in our code where we need it.  I know it’s not as glamorous as pressing the
F5 button and a lot of it you may consider common sense.  However, I hope it helps spark some ideas in
others to create unique debugging solutions.

Literal Debugging

We want to track down the cause of this exception, so I am
going to add a try / catch block around our code.  When an exception is caught, we’ll use a new debugging
method that we created to display the text of the exception.

try

{

    using (SPSite siteCollection = new SPSite(SPContext.Current.Site.ID))

    {

   
    using (SPWeb site = siteCollection.OpenWeb(SPContext.Current.Web.ID))

   
    {

   
        SPList tasksList = site.Lists["Tasks List"];

 

   
        SPListItem newItem = tasksList.Items.Add();

   
        newItem["Title"] =
TitleTextBox.Text;

 

   
        newItem.Update();

   
    }

    }

}

catch (Exception exception)

{

   
DebugUsingLiteral(exception.ToString());

}

 

Our DebugUsingLiteral
method simply adds a literal to the page and dumps the text of the exception to
the page so that you can see it.

private void DebugUsingLiteral(string message)

{

   
Controls.Add(new Literal() { Text = message });

}

 

Here is what the exception looks like now that it is caught.

Not the prettiest solution, but at least we know what the
issue is now.  It cannot find the list as
we had expected.

Comment Debugging

That solution above works but it’s not very user
friendly.  Let’s pretty it up a bit by
writing the exception to an HTML comment. 
This will allow us to view the source of the HTML to see the exception
and the user won’t have to see it.  Let’s
replace our calls to DebugUsingLiteral
with a new method DebugUsingLiteralComments.  Here is what the new method looks like.

private void
DebugUsingLiteralComments(string message)

{

   
Controls.Add(new Literal() { Text = string.Format(“<!– {0} –>”, message) });

}

 

When we try it out, we now no longer see the error message.

Looking at the HTML source of our page, we can find our
exception.

Of course the user has no clue it failed either.  However, we can fix that pretty easily by
adding a new control to our debugging method to display a user friendly error
message.

private void DebugUsingLiteralCommentsUserFriendly(string message, string userFriendlyMessage)

{

   
Controls.Add(new Literal() { Text = string.Format(“<!– {0} –>”, message) });

   
Controls.Add(new Label() { Text = userFriendlyMessage });

}

 

When the user gets the exception now, they see a
more user friendly error message.

Handling verbose debugging

At times, we may also want to write verbose non-exception
information to the screen as well. Now would be a good time to get reacquainted
with the C# compiler directive, #if DEBUG. 
Our strategy here is that if the solution was built using the Visual
Studio debug configuration, we’ll output additional debugging information.  When in release mode, nothing will be logged.  We’ll use the same DebugUsingLiteralComments method that we used above.  Take a look at the snippet below.

#if DEBUG

DebugUsingLiteralComments(“Getting
reference to Tasks List.”);

#endif

SPList tasksList =
site.Lists["Tasks List"];

 

#if DEBUG

DebugUsingLiteralComments(“Creating new
item.”);

#endif

The #if DEBUG tells the compiler to only execute the lines
to output debugging information if the current Visual Studio build
configuration is set to Debug.  When we execute the code, our HTML now has
our debugging lines in it.

Why did we not just put the compiler directives inside the DebugUsingLiteralComments method?  This is just a slight code optimization.  The release version of the code never has to
call the method itself when the debugging configuration is not used.  It may be a minimal performance improvement,
but since you have limited resources in the cloud, it’s probably worth
considering.  I could be totally wrong of
course.

When we are ready to ship the code, we simply
recompile in release mode and the debugging lines are gone.

When
you do compile in release mode, don’t forget to get your .wsp file from the release folder instead of the debug folder.  Another thing to note when uploading all of
these solutions packages to the cloud is that you need to deactivate the
existing solution first prior to uploading a new version of it.  However, you do not need to delete the
existing solution package prior to uploading the new version.

Debugging a using List

The SharePoint Online Developer Guide recommends using a
list for debugging.  This is a great
technique because it allows you to view all of your debugging information in
one place.  Plus, you can take advantage
of all the features list have such as sorting and alerts.  For today’s example, I am going to keep
things simple.  I want to create a new
list with a few relevant columns to collect my information.  In a fully functional solution, we would probably
create site columns, a content type and a dedicated class library to host the
code to write to the list.

Let’s start by defining the information I want
to keep track of in my debugging list. This is on top of the columns we already
have such as Modified Date.

To
save time, I will create this list using the SharePoint UI.  I’ll provide the complete solution including
features to deploy the list using CAML in the future.  We’ll create a custom list named Logs.

After we create the list, I create the columns listed in the
table above (note: Title is already present).

Now we just need a bit of code to write to the log.   We’ll put the logging code in a separate
class that we’ll call CloudLog.  In that class, we’ll create a static method
that takes parameters matching the site columns on our Logs list, title, severity, and description.  We don’t need to pass the URL field since
we can infer that from the HttpContext. 
For severity, I created an
enum for convenience.

public enum CloudLogSeverity

{

   
Information,

   
Warning,

   
Error

}

 

The code of the method itself should look pretty
familiar.  We’re just inserting an item
into a list like before.  Here is what
the class looks like.

using System;

using
System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Web;

 

using
Microsoft.SharePoint;

 

namespace
SharePointOnlineDebugging

{

    public class CloudLog

    {

   
    public static void DebugUsingList(string title, CloudLogSeverity severity, string description)

   
    {

   
        try

   
        {

   
            using (SPSite siteCollection = new SPSite(SPContext.Current.Site.ID))

   
            {

   
                using (SPWeb site =
siteCollection.OpenWeb(SPContext.Current.Web.ID))

   
                {

   
                   
SPList logsList =
site.Lists["Logs"];

 

   
               
    SPListItem newItem = logsList.Items.Add();

   
               
    newItem["Title"] = title;

   
               
    newItem["Severity"] = severity.ToString();

   
               
    newItem["Description"] = description;

 

   
               
    SPFieldUrlValue pageUrlFieldValue = new SPFieldUrlValue();

   
               
    pageUrlFieldValue.Url = HttpContext.Current.Request.Url.ToString();

   
               
    newItem["Url"] = pageUrlFieldValue;

 

   
               
    newItem.Update();

   
                }

   
            }

   
        }

   
        catch (Exception exception)

   
        {

 

   
        }

   
    }

   

}

 

We get a reference to the Logs list and then we just insert a new item.  Once we set the values on the list item we
call SPListItem.Update() to write the
entry to the list.  This code inserts
items into lists which of course has the potential to cause exceptions.  I didn’t want exceptions in our logging code
to affect the rest of the application so currently I have an empty catch block
in the implementation.  I know that’s not
really a good practice, but I really couldn’t think of a good option to catch
additional errors like this.

To call the method, I update the code in our catch block as
follows.

catch (Exception exception)

{

    CloudLog.DebugUsingList(“Error
creating new item.”, CloudLogSeverity.Error, exception.ToString());

}

 

When the exception occurs, an item is logged to
the list.  We can then view the list to
see the details of the exception.

In a complete implementation, I could see additional
overloads of the DebugUsingList
method to serve a variety of needs.  We
could allow the developer to pass in more or less parameters depending on his
or her needs.  There could be methods
that specifically log errors or information. 
Perhaps, we could have methods that write additional data to the list.  There are many possibilities on what we can
do to fully customize our debugging experience.

One thing to note about this approach is that the user
running the application must have write permissions on the Logs list.  If the user
doesn’t, no information can be logged.  To
do this, I stopped permission inheritance on the list and I added contribute
permission (technically more than needed) to the Viewers and Visitors
groups.

To
test my solution, I logged in as a non-administrator, Test User, and generated the error. 
I then confirmed that the item written to the list was created by my Test
User account.

Another
issue to consider with this approach is that you will likely need to perform
some maintenance on this list.  On a
large site with lots of logging, this list could grow quite quickly.  You will need to create filters on the list
or purge it periodically to prevent list throttling.  You also need to be mindful that logging to
the list will use some resources against your quota.  Your quota should be monitored if you intend
to leave logging on for long periods of time.

Debugging with the Developer Dashboard?

When I was coming up with new debugging techniques, the
developer dashboard was originally going to be my recommended solution.  Using the SPMonitoredScope
class allows you to monitor the performance of your code and it allows you to
write directly to the developer dashboard. 
Unfortunately, this class is not available in sandboxed solutions so we
can’t use it with SharePoint Online.  You
still have plenty of other debugging techniques available to you that were
presented in this article though.

Community Involvement

I think there is a great opportunity for the community to
work together and build a great logging framework for SharePoint Online.  The solution I have shown you today is just
the beginning of what could be a grand community driven solution on CodePlex.  The solution would consist of features to
deploy, site columns, content types, the list, as well as classes you can
leverage to do your logging.  If you are
interested in helping out, feel free to contact me.  I think we can build a great solution.