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.