In Part 2 of this series we looked at some of the details of working with Yammer Open Graph items in the CloudTopia app.  In Part 3 we’re going to talk about adding and using Web API 2.1 functionality to a standard out of the box SharePoint App, and then look at what we do with that in CloudTopia.

Here's some quick links to the whole series:

  1. Intro
  2. Open Graph
  3. Web API
  4. Azure Integration
  5. Office 365 Integration
  6. Cortana, Speech and Windows Phone Integration

In CloudTopia I use a Web API REST endpoint for my implementation of virtually everything.  It allows me to create an end user experience free of postbacks, but still access all the functionality of CSOM as well as .NET.  I can use JavaScript and jQuery to manage the front end interface because the code in my Web API controller is doing all the work.  In addition to that, by adding a REST endpoint to my application I open it up to be consumed and/or provide services to other applications.  A good example of this is the Twitter integration.  That process is kicked off by an Azure Scheduler job that makes a GET request on a REST endpoint I set up.  That’s a pretty key use case for Web API in your SharePoint Apps – without it, all of your application functionality is wrapped up in the fairly narrow confines of some browser based application.  By adding a Web API endpoint on top of it, now I can integrate that same functionality into many other applications across my organization or even, as demonstrated with the Azure Scheduler, outside my organization if I wish.

Now, adding the plumbing to support Web API 2.1 is not necessarily easy to find, so let me give you the steps here:

  1. Add the following two NuGet packages to your web application project:  Microsoft ASP.NET Web API 2.2 Core Libraries and Microsoft ASP.NET Web API 2.2 Web Host (NOTE:  the “2.2” refers the current version at the time of this blog post; you may find a more current version).

  2. Add a new class file to the root of your project and call it WebApiConfig.cs.

  3. Add the following code to your WebApiConfig.cs file (NOTE: You can add a different default route for your REST endpoints if you wish, I’m just following common convention here):

 

    public class WebApiConfig

    {

        public static void Register(HttpConfiguration config)

        {

            config.MapHttpAttributeRoutes();

 

            config.Routes.MapHttpRoute("API Default", "api/{controller}/{id}",

                new { id = RouteParameter.Optional });

        }

    }

 

  1. Add this code to Application_Start in Global.asax:

protected void Application_Start(object sender, EventArgs e)

{

//for WebApi support

GlobalConfiguration.Configure(WebApiConfig.Register);

}

Once you’ve done the configuration above, you can add a new Web API Controller Class v2 to your project and start creating your REST endpoints.  Before you get started writing code here a few tips:

  • Make sure the name of your class contains the word “Controller” (i.e. EventsController.cs); otherwise it won’t be found.  That one can drive you a little crazy if you don’t write much Web API and so aren’t familiar with this little nuance.

  • To create an overload inside your controller add a Route attribute and optionally an HTTP verb; that is how I added multiple POST endpoints to my single Web API controller class.  For example I do a POST request to api/events/currentevents to get the list of current events, a POST to api/events to create a new social event, etc.  Here’s an example of what the currentevents route looks like:

 

[Route("api/events/currentevents")]

[HttpPost]

public List<SocialEvent> Get([FromBody]string value)

{

//code goes here

}

  • Make sure your Route attribute uses the same path as a route you defined in WebApiConfig.cs.  For example, if your route definition uses “api/{controller}/{id}, your Route attribute should also start with “api/”.

 Once you have your controller added and configured as described above, calling it from jQuery is quite simple.  Here’s an abbreviated look at the jQuery in my SharePoint App that gets the list of events: 

//some SharePoint vars I get and will explain next

formData = JSON.stringify(formData);

 

$.post("/api/events/currentevents", { '': formData })

.success(function (data)

{

       //code goes here

}).fail(function (errMsg)

{

alert("Sorry, there was a problem and we couldn't get your events: " +

errMsg.responseText);

});

 

One of the biggest challenges when using a REST endpoint as part of your SharePoint App is getting an access token to work with (assuming you are doing more than just app only calls).  I looked three different options for this when I was writing CloudTopia:

  1. Persist token info to storage, like we recommend for the CAM “permissions on the fly” scenario

  2. Persist token info to ViewState

  3. Write out tokens to hidden fields on page

Of these options #1 is the safest and most enterprise-worthy of the bunch.  It also takes the most time and investment to do it right.  Because of the limited time I had to build the CloudTopia application I did not take this approach.  If I were though, I would consider having a method in my REST endpoint called something like RegisterRequest.  I could imagine calling a method like that and passing in a SharePointContextToken as I described in this post here:  http://blogs.technet.com/b/speschka/archive/2013/07/30/security-in-sharepoint-apps-part-4.aspx.  With the SharePointContextToken I have a) a guaranteed unique cache key for it and b) a refresh token that I can use to obtain an access token.  So when my RegisterRequest method was called I could then store that somewhere, like SQL Azure or whatever.  Then I could require that any calls into my REST endpoints provide the cache key, and all I have to do is look up what I’ve stored and if there’s something there, use the refresh token to get an access token and go to work.  This is just one idea I had, you may have others of your own.

Given my limited time, I chose to try both option 2 and 3.  Option 2 was really something I just wanted to play with to see if there would be any issues in using it.  So in that case I took the access token I got and wrote it to ViewState, and then I used it for one button in the page, which cleans the app up (i.e. deletes the hidden list I use to track new events).  I’m happy to report that it worked fine so if you want to go that way and you are doing your code in post back events it should work fine.  That’s really the key – you switch to a post back model if you want to use values from ViewState.

Primarily what I did was option 3.  I wrote both the SharePoint site Url as well as the access token to the page to some hidden fields, and then I pass those variables in to my REST calls.  It all travels over SSL, the access token has a limited lifetime, etc. so it was a reasonable choice given what I had to work with. 

The end-to-end implementation of if then went something like this:

 

  • I had client side script that looks like this:

//get the hiddens

var hostUrl = $("#hdnHostWeb").val();

var accessToken = $("#hdnAccessToken").val();

 

//create the JSON string to post

var formData = "{hostUrl:" + hostUrl + "," +

"accessToken:" + accessToken + "}";

 

//make it POST ready

formData = JSON.stringify(formData);

 

//call my REST endpoint

$.post("/api/events/currentevents", { '': formData })

 

  • In my REST endpoint I parsed out the JSON that was sent in like this (NOTE:  ParseJson is just a custom method I wrote for my SocialEvent class):

SocialEvent se = SocialEvent.ParseJson(value);

 

  • The SocialEvent class has a hostUrl and accessToken property, so I just used them when calling methods that used CSOM to work with SharePoint:

List<SocialEvent> results = GetEventListItems(se.hostUrl, se.accessToken);

 

  • In my code that uses CSOM I created the ClientContext using the hostUrl and accessToken like this:

using (ClientContext ctx = TokenHelper.GetClientContextWithAccessToken(hostUrl, accessToken))

 

There you have it – that’s a roadmap for how to add Web API 2.x support to your SharePoint Apps.  I’m becoming a pretty big fan of this approach because it provides so much flexibility for making a client experience exactly like you want it, plus it opens up the capability to integrate all of your application functionality across other applications.  Now that we’ve wrapped up this piece of plumbing, in Part 4 of this series we’ll take a look at the Azure integration points.