Watching for Snow

I’m in Toronto this week presenting at the annual SharePoint Summit conference and watching out for the impending blizzard. I presented an SPO session this morning that walked through an overview of Office 365 (the new cloud-hosted productivity offering from Microsoft). The session covered some basics of Office 365 and then walked through a few examples of developing for SPO using a variety of approaches:

  1. OOB capabilities such as Excel Services/REST URI to build a sales dashboard.
  2. Declarative workflow, starting from Visio and then exporting to SharePoint Designer and finally publishing to SharePoint.
  3. Silverlight and Client Object Model to interact with SharePoint lists.
  4. Bing Maps and Client Object Model to display list data.
  5. Sandboxed solutions to illustrate how to drop WSPs to a solutions gallery and then interact with a list.

The deck for the session could be found here:

Some additional information on a couple of the examples are below.

Re the Sales Dashboard

  • The ability to create an Excel 2010 document and then have named items such as tables and charts—as in the figure below.

image

  • When you’ve created the Excel SS, upload to SharePoint by clicking File, Save and Send, Save to SharePoint.
  • Before you save to SharePoint, make sure you click the Publish Options. As per the figure below, you can see that you’ll need to select the objects in the chart and then save to SharePoint. Doing this enables you to leverage the Excel Services capabilities in SharePoint.

image

  • Once you’ve uploaded the Excel document to a SharePoint document library, you can now create a new Excel Web Access web part (click Site Actions, Edit Page, Add a web part, and in the Business Data category select Excel Web Access).
  • You’ll now be able to configure the web part by clicking Click here to open tool pane where you can add a reference to the worksheet (in the Worksheet field) and add a reference to a specific object (such as a named range or chart) in the Excel document.
  • You can do this a couple more times and add references to the Chart object or you can create an Image Viewer web part and leverage the REST URI to point directly to the Chart object, e.g. https://spsites.microsoft.com/_vti_bin/ExcelRest.aspx/sites/stefox/Shared%20Documents/KPIs.xlsx/Model/Charts('Chart%201').
  • The result is a dashboard similar to the below.

image

The nice thing about this is there is no code here. However, what if you do want to create some code and deploy it to SharePoint Online? You absolutely can, and fortunately there are multiple things that you can do. For example, you could use the SP Client Object Model or server object model to interact with lists or libraries (within the purview of a site collection). You can deploy Silverlight applications to SharePoint to, for example, build out BI apps that leverage the Silverlight toolkit charts. And you can also deploy event receivers, lists, master pages, and so on—all programmatically and all through a sandboxed solution.

The key to the sandboxed solution is the Solutions Gallery. You need to develop your WSP locally and then upload to the Solutions Gallery. This means you have to have a local instance of SharePoint along with your tools (i.e. VS 2010) set up for you to build your apps with. For example, create a new VS 2010 project, select Empty SharePoint Project as the template and ensure you configure it as a sandboxed solution—and not a full-trust, farm-level solution. Then, add a new item to the project and make it a web part.

Double-click the web part class file to add some code—such as the below. (Yes, this is long-hand code…you’d want to make your HTML write code a little more elegant and not overuse the LiteralControls.)

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 Store_Location_Web_Part.AddStoreWebPart
{
    [ToolboxItemAttribute(false)]
    public class AddStoreWebPart : WebPart
    {
        Label lblTitle = new Label();
        Label lblStoreTitle = new Label();
        Label lblStoreName = new Label();
        Label lblStoreAddress = new Label();
        Label lblStorePhoneNum = new Label();
        Label lblStoreLatitude = new Label();
        Label lblStoreLongitude = new Label();
        Label lblStoreHours = new Label();

        TextBox txtbxStoreTitle = new TextBox();
        TextBox txtbxStoreName = new TextBox();
        TextBox txtbxStoreAddress = new TextBox();
        TextBox txtbxStorePhoneNum = new TextBox();
        TextBox txtbxStoreLatitude = new TextBox();
        TextBox txtbxStoreLongitude = new TextBox();        TextBox txtbxStoreHours = new TextBox();

        LinkButton lnkbtnSubmit = new LinkButton();
        LinkButton lnkbtnAddDefaults = new LinkButton();

        protected override void CreateChildControls()
        {
            lblTitle.Text = "Add a New Contoso Store";
            lblTitle.Font.Bold = true;
            lblTitle.Font.Size = 14;

            lblStoreTitle.Text = "Title: ";
            lblStoreName.Text = "Name: ";
            lblStoreAddress.Text = "Address: ";
            lblStorePhoneNum.Text = "Phone Num: ";
            lblStoreLatitude.Text = "Latitude: ";
            lblStoreLongitude.Text = "Longitude: ";
            lblStoreHours.Text = "Hours: ";
            lnkbtnSubmit.Text = "Add New";
            lnkbtnAddDefaults.Text = "Add Defaults";

            txtbxStoreTitle.Width = 175;
            txtbxStoreName.Width = 175;
            txtbxStoreAddress.Width = 175;
            txtbxStorePhoneNum.Width = 175;
            txtbxStoreLatitude.Width = 175;
            txtbxStoreLongitude.Width = 175;
            txtbxStoreHours.Width = 175;

            this.Controls.Add(lblTitle);
            this.Controls.Add(new LiteralControl("<table>"));

            this.Controls.Add(new LiteralControl("<tr><td>"));
            this.Controls.Add(lblStoreTitle);
            this.Controls.Add(new LiteralControl("</td><td>"));
            this.Controls.Add(txtbxStoreTitle);
            this.Controls.Add(new LiteralControl("</td></tr>"));

            this.Controls.Add(new LiteralControl("<tr><td>"));
            this.Controls.Add(lblStoreName);
            this.Controls.Add(new LiteralControl("</td><td>"));
            this.Controls.Add(txtbxStoreName);
            this.Controls.Add(new LiteralControl("</td></tr>"));

            this.Controls.Add(new LiteralControl("<tr><td>"));
            this.Controls.Add(lblStoreAddress);
            this.Controls.Add(new LiteralControl("</td><td>"));
            this.Controls.Add(txtbxStoreAddress);
            this.Controls.Add(new LiteralControl("</td></tr>"));

            this.Controls.Add(new LiteralControl("<tr><td>"));
            this.Controls.Add(lblStorePhoneNum);
            this.Controls.Add(new LiteralControl("</td><td>"));
            this.Controls.Add(txtbxStorePhoneNum);
            this.Controls.Add(new LiteralControl("</td></tr>"));

            this.Controls.Add(new LiteralControl("<tr><td>"));
            this.Controls.Add(lblStoreLatitude);
            this.Controls.Add(new LiteralControl("</td><td>"));
            this.Controls.Add(txtbxStoreLatitude);
            this.Controls.Add(new LiteralControl("</td></tr>"));

            this.Controls.Add(new LiteralControl("<tr><td>"));
            this.Controls.Add(lblStoreLongitude);
            this.Controls.Add(new LiteralControl("</td><td>"));
            this.Controls.Add(txtbxStoreLongitude);
            this.Controls.Add(new LiteralControl("</td></tr>"));

            this.Controls.Add(new LiteralControl("<tr><td>"));
            this.Controls.Add(lblStoreHours);
            this.Controls.Add(new LiteralControl("</td><td>"));
            this.Controls.Add(txtbxStoreHours);
            this.Controls.Add(new LiteralControl("</td></tr>"));

            this.Controls.Add(new LiteralControl("<tr><td>"));
            this.Controls.Add(lnkbtnSubmit);
            this.Controls.Add(new LiteralControl("</td><td>"));
            this.Controls.Add(lnkbtnAddDefaults);
            this.Controls.Add(new LiteralControl("</td></tr>"));

            this.Controls.Add(new LiteralControl("</table>"));

            lnkbtnSubmit.Click += new EventHandler(lnkbtnSubmit_Click);
            lnkbtnAddDefaults.Click += new EventHandler(lnkbtnAddDefaults_Click);
        }

        void lnkbtnAddDefaults_Click(object sender, EventArgs e)
        {
            PopulateTextboxes();
        }

        private void PopulateTextboxes()
        {
            txtbxStoreTitle.Text = "23";
            txtbxStoreName.Text = "Contoso Tacoma Central";
            txtbxStoreAddress.Text = "Tacoma Dome Shopping Annex";
            txtbxStorePhoneNum.Text = "253-555-3212";
            txtbxStoreLatitude.Text = "47.2530556";
            txtbxStoreLongitude.Text = "-122.4430556";
            txtbxStoreHours.Text = "12";
        }

        void lnkbtnSubmit_Click(object sender, EventArgs e)
        {
            SPSite siteCollection = SPContext.Current.Site;
            SPWeb mySite = SPContext.Current.Web;
            SPListItemCollection listItems = mySite.Lists["Store Locations"].Items;
            SPListItem item = listItems.Add();

            item["Title"] = "23";
            item["StoreName"] = "Contoso Tacoma Dome";
            item["StoreAddress"] = "Tacoma Dome Annex Shopping Mall, Tacoma, Washington, United States";
            item["StorePhone"] = "253-442-1029";
            item["Latitude"] = "47.2530556";
            item["Longitude"] = "-122.4430556";
            item["Hours"] = "12";
            item.Update();
        }
    }
}

Note that you need to create a list in the SharePoint site called “Store Locations” and then ensure it has the same fields as in the code (i.e. Title, StoreName, StoreAddress, StorePhone, Latitude, Longitude, and Hours). The right-click the web part and select Package, navigate to the ~/bin/debug directory and copy the path from Windows Explorer. Navigate to your SharePoint Online site, click Site Actions, Site Settings and then select Solutions. Click the Solutions tab and Upload Solutions to browse and upload your WSP (you can paste the folder path you copied earlier on).

image

You can now navigate to a page and add the web part as you would any normal, custom web part. The result is a web part that is similar to the screenshot below—where the Add a New Contoso Store web part pushed data into a list.

image

You’ll note the Bing Maps Silverlight application. If you’re interested in doing that, you can check out this blog post here: http://blogs.msdn.com/b/steve_fox/archive/2010/11/03/sharepoint-amp-bing-maps-at-sharepoint-connections-las-vegas.aspx. It has additional code samples you can use to hook up the Silverlight app to the list where the location data is located.

I have a few more code samples that I will post over time, but hopefully this gives you a high-level sense of how you get a simple web part into SharePoint Online.

Steve