Push Notifications with SharePoint 2013-based Windows Phone apps

Setting up push notifications for your SharePoint Windows Phone app is fairly straight-forward. Push notifications with SharePoint uses the same Microsoft Push Notification Service (MSPNS) to create a communications channel from the server to the device. The following code sets up an MSPNS channel:

public void Register(ClientContext context)
{
    _currentContext = context;

    HttpNotificationChannel channel = HttpNotificationChannel.Find(CHANNEL_NAME);

    if (channel == null)
    {
        channel = new HttpNotificationChannel(CHANNEL_NAME);

        channel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(channel_ChannelUriUpdated);
        channel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(channel_ErrorOccurred);
        channel.ShellToastNotificationReceived += new EventHandler<NotificationEventArgs>(channel_ShellToastNotificationReceived);

        channel.Open();
        channel.BindToShellToast();
    }
    else
    {
        channel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(channel_ChannelUriUpdated);
        channel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(channel_ErrorOccurred);
        channel.ShellToastNotificationReceived += new EventHandler<NotificationEventArgs>(channel_ShellToastNotificationReceived);
    }
}

 

If a channel hasn't yet been created, then we create it, add event handlers for events that we need to handle and then open the channel. The event handler ShellToastNotificationReceived is used so that we can handle the notification while the app is running. If the app is not running, the toast will be handled automatically by calling BindToShellToast().

When MSPNS has created a channel and assigned it a URI, we need to then create a notification subscription in SharePoint:

void channel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e)
{
    Web web = _currentContext.Web;
    string channelUri = e.ChannelUri.ToString();

    PushNotificationSubscriber subscriber;

    if (!web.DoesPushNotificationSubscriberExist(App.Settings.AppDeviceID).Value)
    {
        subscriber = web.RegisterPushNotificationSubscriber(App.Settings.AppDeviceID, channelUri);
    }
    else
    {
        subscriber = web.GetPushNotificationSubscriber(App.Settings.AppDeviceID);
        subscriber.ServiceToken = channelUri;
    }

    subscriber.SubscriberType = SUBSCRIBER_TYPE;
    subscriber.Update();

    _currentContext.ExecuteQueryAsync(null,null);
}

 

First we check to see if the notification subscriber already exists. Subscriptions are stored in a list in SharePoint called PushNotificationSubscriptionStore. This is a hidden list that you can't get to through the UI; however, it does show up in the ListData.svc OData service. To see what fields are in the list, review the service's metadata (ex/ http://mobile-apps.fabrikam.com/sites/Team%20Site/_vti_bin/listdata.svc/$metadata). This list contains PushNotificationSubscriptionStoreItem items. The DeviceIdentifier field is what you can use to store the GUID that was generated for the device/app and the ServiceToken field should be used to store the channel URI. Also note that you should probably come up with distinct SubscriberType values. Since all of these notification subscriptions are stored in a single list, this is the simplest way for you to distinguish which notification to send for each application notification. Once these fields are set, we use ClientContext.ExecuteQueryAsync() to save the values.  One other thing to mention, don’t forget to activate the Push Notifications site feature on the site where you’ll be using push notifications (this should actually be the first thing you do).

To handle unregistering for the push notification, you need to unregister the notification subscription from SharePoint:

private void ButtonClear_Click(object sender, RoutedEventArgs e)
{
    App.Settings.ClearSettings();
    PushNotificationRegistration registration = new PushNotificationRegistration();
    registration.Unregister();
}

 

The Unregister method of my PushNotificationRegistration class closes and disposes the channel I created when the user initially registered:

public void Unregister()
{
    HttpNotificationChannel channel = HttpNotificationChannel.Find(CHANNEL_NAME);
    if (channel != null)
    {
        channel.Close();
        channel.Dispose();
    }
}

Once this is ready, then on the server, all you have to do is to find all the notification subscribers that you need to send a notification to and send the notification out using the same code you'd normally use to send push notifications out to other Windows Phone apps. For this app, I decided to handle this in an Event Receiver and send notifications out when an item is added or updated in the Products list:

public class ProductsListEventReceiver : SPItemEventReceiver
{
    /// <summary>
    /// An item is being added.
    /// </summary>
    public override void ItemAdding(SPItemEventProperties properties)
    {
        base.ItemAdding(properties);
        SendNotification("New Product Added", properties); 
    }

    /// <summary>
    /// An item is being updated.
    /// </summary>
    public override void ItemUpdating(SPItemEventProperties properties)
    {
        base.ItemUpdating(properties);
        SendNotification("Product Updated", properties); 
    }

    private void SendNotification(string title, SPItemEventProperties properties)
    {
        SPPushNotificationSubscriberCollection subscribers = properties.Web.PushNotificationSubscribers;
        foreach (SPPushNotificationSubscriber subscriber in subscribers)
        {
            if (!string.IsNullOrEmpty(subscriber.SubscriberType) && subscriber.SubscriberType.Equals(
"ProductAlerts", StringComparison.InvariantCultureIgnoreCase))
            {
                HttpWebRequest sendNotificationRequest = (HttpWebRequest)WebRequest.Create(subscriber.ServiceToken);
                sendNotificationRequest.Method = "POST";
                string toastMessage = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                "<wp:Notification xmlns:wp=\"WPNotification\">" +
                "<wp:Toast>" +
                "<wp:Text1>" + title + "</wp:Text1>" +
                "<wp:Text2>" + properties.ListItem.Title + "</wp:Text2>" +
                "</wp:Toast> " +
                "</wp:Notification>";
                byte[] notificationMessage = Encoding.Default.GetBytes(toastMessage);
                sendNotificationRequest.ContentLength = notificationMessage.Length;
                sendNotificationRequest.ContentType = "text/xml";
                sendNotificationRequest.Headers.Add("X-WindowsPhone-Target", "toast");
                sendNotificationRequest.Headers.Add("X-NotificationClass", "2");
                try
                {
                    using (Stream requestStream = sendNotificationRequest.GetRequestStream())
                    {
                        requestStream.Write(notificationMessage, 0, notificationMessage.Length);
                    }
                    HttpWebResponse response = (HttpWebResponse)sendNotificationRequest.GetResponse();
                }
                catch
                {
                    //TODO: log error 
                }
            }
        }
    } 

}
 

Note that it's probably not a good idea to do a foreach loop over the SPPushNotificationSubscriberCollectionif there's going to be thousands of items in that list. I did this for the sake of simplicity. Also, LINQ to SharePoint won't work on this list. The only way you might be able to do a more efficient filtering is through a CAML query, though I didn't test this.

Once this feature is installed and the user has registered for push notifications in this app, the results look like this:

toast

One thing to be aware of is that with Windows Phone apps, there's no event notification for when your app is uninstalled. Given this, you probably need some way to determine on the server if a notification subscription should be deleted (if it hasn't been used in a while). Otherwise, you might be flooding MPNS with attempts to send a notification to a channel that is no longer accessible.

If you want the full source code to this, please tweet a link to this post and then send me an email (bart.tubalinal at deviantpoint dot com). I will then email you the source code for both the phone app project and the event receiver project.

Building Windows Phone apps with SharePoint 2013

With SharePoint 2013, Microsoft has included a set of Windows Phone assemblies that will allow you to quickly build native Windows Phone applications that can communicate and interact with data in SharePoint. The two assemblies you need to reference in your WP application are Microsoft.SharePoint.Client.Phone and Microsoft.SharePoint.Client.Phone.Runtime. Both assemblies are located in C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\TEMPLATE\LAYOUTS\ClientBin.

Authentication to the SharePoint site is handled using the Authenticator class. Windows Phone apps with SharePoint supports four authentication modes: Windows Authentication (Default), Forms Authentication, Anonymous, and using Microsoft Online. I have not tested the Microsoft Online-based Authentication but I believe it's used in conjunction with the Microsoft.SharePoint.Client.BrowserLogin class (in the Runtime assembly), which is an application page that will load when using this type of authentication.

For Windows Authentication, note that either Forefront UAG must be used or the web application must be configured to use Basic Authentication.

The following is an example of retrieving data from a SharePoint list:

public void LoadData() 
{ 
    currentDispatcher = Application.Current.RootVisual.Dispatcher; 
    //obviously, these shouldn't be hard-coded. 
    ClientContext context = new ClientContext(new Uri("http://url-to-sharepoint-site")); 
    context.Credentials = new Authenticator("Username", "Password", 
    "Domain"); 
    Site site = context.Site; 
    Web web = site.RootWeb; 
    List productsList = web.Lists.GetByTitle("Products"); 
    CamlQuery camlQuery = new CamlQuery(); 
    camlQuery.ViewXml = "<View><RowLimit>100</RowLimit></View>"; 
    productItems = productsList.GetItems(camlQuery); 
    context.Load(productItems); 
    context.ExecuteQueryAsync(ClientRequestSucceededEventHandler, ClientFailedEventHandler); 
    this.IsDataLoaded = true; 
} 

 

If you've done any coding with CSOM or the SharePoint Javascript object model, the above code should be very familiar. It uses the same classes like ClientContext, Site, Web, etc to interact with SharePoint. Like all Windows Phone apps, requests must be done asynchronously to prevent locking the UI thread – which means you need to use ExecuteQueryAsync instead of ExecuteQuery or you will get an Exception.

The important part of the code is that the ClientContext.Credentials is set to an instance of the Authenticator class.

This is what the success handler looks like:

void ClientRequestSucceededEventHandler(object sender, ClientRequestSucceededEventArgs e) 
{ 
    currentDispatcher.BeginInvoke(() => 
    { 
        foreach (var item in productItems) 
        { 
            string trimmedDescription = item["Description"].ToString(); 
            if (trimmedDescription.Length > 150) trimmedDescription = trimmedDescription.Substring(0, 149) + " ..."; 
            this.Items.Add( 
                new ItemViewModel() 
                { 
                    Title = item["Title"].ToString(), 
                    Description = trimmedDescription, 
                    ImageUrl = new Uri((item["Image"] as FieldUrlValue).Url, UriKind.Absolute), 
                    Color = item["Color"].ToString() 
                } 
            ); 
        } 
    }); 
    this.IsDataLoaded = true; 
} 

 

Again, this handler is typical of what you would use with CSOM/JavaScript. When this handler executes, we need to move back to the UI thread to add these items and for it to display in our view. That's what the line currentDispatcher.BeginInvoke(() => {}) is for.

When the code executes, this is what the Phone app looks like:

all-products

This data is being pulled from a SharePoint list:

image

With Windows Phone apps, there is full support for CRUD operations on list data. This also includes external lists. There is also support for push notifications, which I'll cover in the next blog post. I’ll also be sharing the full source code for this little app in the next post.

Using Windows Azure AppFabric Access Control Service in an iPhone App to Integrate with Facebook

Intro

This is the third post in a series that shows how to use Windows Azure as a platform that provides key services for native mobile applications. In the first two parts of the series, I walked through the process of creating my SpeakEasy app, a fictitious iPhone app that keeps track of speakers and their events.

In this post, I will walk through how to use the Azure AppFabric Access Control Service (ACS). ACS is a service that provides federated authentication using claims. ACS provides support for different identity providers, including Facebook, Windows Live, Google, Yahoo!, and ADFS 2.0 (and other WS-Federation identity providers). In this scenario, I will be using Facebook as an identity provider. Rather than force the user to log in using their Facebook account right away, I will only ask the user to log in when they want to share the details of an event on their Facebook wall. When they attempt to share the event, they will first have to log in using their Facebook account and then, by using the token received from Facebook (which will be provided as a claim), I will show how to post a message on the user's wall.

As a reminder, this series includes:

Facebook Application Setup

To start with, we need to create a Facebook application:

  1. Go to http://www.facebook.com/developers and log in.
  2. Click the Create New App button.
  3. In the Create New App dialog, enter an appropriate name and the optional namespace. I have configured my application with the following settings:
    • App Name: SpeakEasy iPhone App from DeviantPoint
    • App Namespace: speakeasy-dp.
    • This is optional but if you want to use Facebook’s Open Graph to post different Actions and define custom Object Types, you’ll need a namespace (I presume to prevent naming collisions).

After you have agreed to the Facebook Platform Policies agreement and clicked the Continue button, you will be taken to your app’s settings page. On this page are two very important pieces of information: the App ID and App Secret. Make a copy of both values as this will be used later on in the ACS setup. The rest of the application configuration is as follows:

  • Contact Email: <my email>
  • Website Site URL: https://<ACS-Service-Namespace>.accesscontrol.windows.net.
    • This is the URL that Facebook will redirect to after the user has successfully logged in. While you’re debugging your application, it’s ok to configure this section and set the URL to your Azure ACS service namespace URL (details in following section). However, when you’ve published your app to the App Store, you’ll want to delete this section and then configure the Native iOS App section correctly to point to your app in the app store.

ACS Setup

Configuring a Service Namespace

  1. Log in to the Azure Management Portal and go to the Service Bus, Access Control & Caching section.
  2. Select Services > Access Control from the left pane and click on the New menu item from the ribbon. My Service Namespace configuration looks like this:

image

The end result of this will be an ACS URL for my namespace: https://speakeasy.accesscontrol.windows.net.

Once the Service Namespace has been created, you will be redirected to the Access Control Service management portal for your new namespace.

Configuring Facebook as an Identity Provider

The next step is configuring your Identity Providers (idP). In this example, we’ll only be using Facebook as our idP. However, you can configure multiple idPs to allow your users to log in using different idP services, like Facebook, Google, Yahoo, Windows Live, and ADFS 2.0.

  1. Click on the Identity Providers link under Trust Relationships in the left pane.
  2. Click on the Add link.
  3. Select Facebook Application from the custom identity provider section and click Next.
  4. Configure the following settings:
    • Display name: Facebook
    • Application ID: this is one of the values that you should have copied from the Facebook Application Setup. Enter that value here.
    • Application secret: this is one of the values that you should have copied from the Facebook Application Setup. Enter that value here.
    • Application permissions:email, publish_stream
      • The application permissions field is used to tell Facebook what permissions your app will need. The email is given by default. The publish_stream permission will allow our app to post on the user’s behalf on his/her newsfeed. Here is a list of all application permissions you can request.
  5. Click Save.

Configuring a Relying Party Application

The next step is to configure a relying party application. A relying party application is an application that trusts the identity provider and consumes the claims made by that identity provider about the user.

  1. Click on the Relying party applications under Trust Relationships in the left pane.
  2. Click on the Add link.
  3. The following are the configuration settings I used for my relying party application:
    • Name: speakeasy.deviantpoint.com
    • Mode: manual
    • Realm: uri:speakeasy.deviantpoint.com
    • Return URL:empty
      • Normally, this is where ACS will redirect your application to after the user has successfully logged in. Since we’re building a native iPhone app, this setting isn’t needed. However, it is sometimes still a good idea to set this to a web page that you’ve built that can take the incoming claims and do something with them. I like to set this to a page on my site where I have some code to read the incoming claims so that I am able to look at them in case I need to debug something.
    • Error URL: empty
    • Token Format:SWT
      • This setting is important. Originally, I had this set to SAML 2.0 but I realized after some debugging efforts that the Windows Azure Toolkit for iOS is expecting the format to be SWT (Simple Web Token).
    • Token Encryption Policy: None
    • Token Lifetime: 600 (secs)
    • Identity Providers: Facebook
    • Rule Groups: Create New Rule Group
    • Token Signing: Use Service Namespace Certificate
  4. Click Save.

Configuring Rule Groups

Rule Groups determine how incoming claims from the identity provider are mapped to output claims delivered to the relying party application.

  1. Click on Rule groups under Trust Relationships in the left pane.
  2. Click the Generate link and select the Facebook identity provider.

Clicking the Generate link will create a default set of rules for the identity provider. ACS is smart enough to tell a standard set of claims that most of the idPs provide. If the idP provided more claims than what was generated, then you can add those claims as well. Similarly, if there are claims that your relying party application doesn’t need, you can remove them as well.

Assuming you’ve set up the Facebook application and ACS (identity provider, relying party application, and rule groups) correctly, then you should be able to use the link to an ACS-hosted login page, found in the Application Integration section under Development in the left pane, to test the process. Note that unless you configured a Return URL for the Relying Party Application, you will get an ACS50011: The RP ReplyTo address is missing.’ error. It’s probably best to configure a Return URL at first for testing purposes to make sure your setup is correct.

Using ACS in the iPhone App

Modifying the Windows Azure iOS Toolkit

Now that the set up is complete, we can start to use ACS in the SpeakEasy app – except for one little detail: if you downloaded the iOS toolkit from the Master branch on Github, the toolkit currently filters out any claims that don’t start with a prefix of ‘http://schemas.xmlsoap.org/ws/2005/05/identity/claims/’. Fortunately, you have two options. The first option is to download the toolkit from the Develop branch. This branch removes the check for this prefix and just passes any claims through. The second option is to just modify the source code yourself. This is the option I took since I wasn’t sure exactly what other changes have been made to the Develop branch and I didn’t want to introduce any unknowns.

If you’re modifying the source code, find the file WACloudAccessToken.m. Around line 80, you will see the following code:

  1: 
  2: NSString* claimsPrefix = @"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/";
  3: 			
  4: for(NSString* part in [_securityToken componentsSeparatedByString:@"&"])
  5: {   
  6: 	NSRange split = [part rangeOfString:@"="];
  7: 	if(!split.length)
  8: 	{
  9: 		continue; // weird
 10: 	}
 11: 	
 12: 	NSString* key = [[part substringToIndex:split.location] URLDecode];
 13: 	NSString* value = [[part substringFromIndex:split.location + 1] URLDecode];
 14: 	
 15: 	if([key hasPrefix:claimsPrefix])
 16: 	{
 17: 		key = [key substringFromIndex:claimsPrefix.length];
 18: 		[claims setObject:value forKey:key];
 19: 	}
 20: }
 21: 
 22: _claims = [claims copy];

 

Change this code to comment out the offending lines:

  1: //NSString* claimsPrefix = @"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/";
  2: 
  3: for(NSString* part in [_securityToken componentsSeparatedByString:@"&"])
  4: {   
  5: 	NSRange split = [part rangeOfString:@"="];
  6: 	if(!split.length)
  7: 	{
  8: 		continue; // weird
  9: 	}
 10: 	
 11: 	NSString* key = [[part substringToIndex:split.location] URLDecode];
 12: 	NSString* value = [[part substringFromIndex:split.location + 1] URLDecode];
 13: 	
 14: // if([key hasPrefix:claimsPrefix])
 15: // {
 16: // key = [key substringFromIndex:claimsPrefix.length];
 17: 		[claims setObject:value forKey:key];
 18: // }
 19: }
 20: 
 21: _claims = [claims copy];

 

Rebuild the toolkit and re-add a reference to the SpeakEasy project.

UI Changes

Now that the Toolkit is ready, we want to add the ability for the user to post an event’s details to his Facebook newsfeed. The easiest place to start is to make changes to the user interface,

Storyboard Changes

  1. Open up the MainStoryboard.storyboard file and find the Event Details view.
  2. From the Object library, drag a Bar Button Item to the navigation bar.
  3. Select the Bar Button Item and change the Identifier to Action in the Attributes Inspector.
  4. Add a View Controller from the Object library to the Storyboard.
  5. Select the View Controller and change the Top Bar to Navigation Bar and the Bottom Bar to Tab Bar.
  6. Change the Navigation Item’s title to Post to Facebook.
  7. Add a Text View and a Round Rect Button from the Object library to the new view.
  8. Resize the Text View to be about 1/3 of the height of the view and almost the full width.
  9. Change the text of the button to Post!.
  10. CTRL+Drag from the Event Details View Controller to the Post to Facebook View Controller.
  11. Select Push for the Segue type.
  12. Set the segue identifier to PostToFacebookSegue.

The new part of the storyboard should now look like this:

image

PostToFacebookViewController

Now we need a custom view controller that will interact with the new Post To Facebook view.

  1. From the Project navigator, right-click the ViewControllers group and select New File.
  2. Select the UIViewController subclass template and click Next.
  3. Name the class PostToFacebookViewController as a subclass of UIViewController.
  4. Click Next a few times until the .h and .m files are created.
  5. Open the .h file and add #import statements for SEEvent.h and WACloudAccessToken.h.
  6. Add the following code to the interface definition:
  1: @property(nonatomic, retain) WACloudAccessToken *acsToken;
  2: @property(nonatomic, retain) SEEvent *event; 
  3: @property(nonatomic, retain) IBOutlet UITextView *messageTextView;
  4: 
  5: -(IBAction)postMessage:(id)sender;

 

The WACloudAccessToken is a class from the Windows Azure iOS Toolkit that represents an ACS access token.

The IBAction postMessage: is the action that will be called when the Post! button is pushed by the user. Synthesize the properties in the .m file and connect the two outlets to their interface counterparts in the storyboard. Add the postMessage: method to PostToFacebookViewController.m but just leave the implementation blank for now.

EventDetailsViewController

Now we need to add code to handle transitioning from the Event Details View to the Post To Facebook View. To do this, we need to modify the EventDetailsViewController.

  1. Open EventDetailsViewController.hand add the following field:
    • WACloudAccessControlClient *_acsClient;
  2. Add the following method:
    • -(IBAction)shareButtonPressed:(id)sender;
    This method is the event handler for when the user clicks on the Action button we added in the storyboard for this view.
  3. Open the EventDetailsViewController.m.
  4. Modify viewDidLoad so it looks like the following:
  1: - (void)viewDidLoad
  2: {
  3:     [super viewDidLoad];
  4:     
  5:     _acsClient = [WACloudAccessControlClient accessControlClientForNamespace:@"speakeasy" 
  6:                                                                        realm:@"uri:speakeasy.deviantpoint.com"];
  7: }

 

The above code is where we use the WACloudAccessControlClient class provided by the iOS Azure toolkit to create a client we can use to hit the ACS service. The namespace and realm passed in are the namespace/realm that was configured as part of the ACS setup.

Modify the prepareForSegue:sender: method so it looks like the following:

  1: - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
  2: {
  3: 	if ([segue.identifier isEqualToString:@"EventPresenterSegue"])
  4: 	{
  5: 		PresenterDetailsViewController *presenterDetailsViewController = segue.destinationViewController;  
  6: 		presenterDetailsViewController.speaker = self.presenter;
  7: 	}
  8:     else if ([segue.identifier isEqualToString:@"PostToFacebookSegue"])
  9:     {
 10:         PostToFacebookViewController *postToFacebookViewController = segue.destinationViewController;
 11:         postToFacebookViewController.event = self.event;
 12:         postToFacebookViewController.acsToken = [WACloudAccessControlClient sharedToken];
 13:     }
 14: }

In the above code, we just add a new condition for the new segue we added. If the segue we’re trying to perform is the segue to move to the Facebook view, then we pass the event and the access token (which is available from the WACloudAccessControlClient after the user has successfully signed in) to that view.

Finally, to handle the Action button being clicked, add this method to the bottom of the file:

  1: -(IBAction)shareButtonPressed:(id)sender
  2: {  
  3:     [_acsClient showInViewController:self allowsClose:YES withCompletionHandler:^(BOOL authenticated) 
  4:     {   
  5:         if(authenticated) 
  6:         {
  7:             [self performSegueWithIdentifier:@"PostToFacebookSegue" sender:self];
  8:         }        
  9:     }];    
 10: }

 

This method calls the showInViewController:allowsClose:withCompletionHandler method on the WACloudAccessControlClient instance. When the method runs after the button is clicked, the facebook login screen will be shown to the client:

image image

After the user has successfully logged in, the completion handler code will run which basically checks to see if the user is logged in and if so, performs the segue to the Post To Facebook view.

Handling the segue to PostToFacebookViewController

In PostToFacebookViewController.m, add the following to viewDidLoad to add a default message to the Text View in the view:

  1: - (void)viewDidLoad
  2: {
  3:     [super viewDidLoad];
  4:     
  5:     messageTextView.text = [NSString stringWithFormat:@"I'll be attending %@ presented by %@ on %@ in %@",
  6:                             _event.eventName, _event.speakerName, _event.eventDateAsString, _event.eventLocation];
  7: }

 

This is a sample of what the view looks like when it is first loaded from the Event Details View:

image

Finally, to post the actual message to Facebook when the Post button is clicked, modify postMessage to look like the following:

  1: -(IBAction)postMessage:(id)sender
  2: {
  3:     NSString *accessToken = [acsToken.claims objectForKey:@"http://www.facebook.com/claims/AccessToken"];
  4:     NSURL *url = [[NSURL alloc] initWithString:[[NSString alloc] initWithFormat:@"https://graph.facebook.com/me/feed?access_token=%@&message=%@", 
  5:                                                 accessToken,  [messageTextView.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
  6:     
  7:     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
  8:     [request setHTTPMethod:@"POST"];
  9:     
 10:     NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
 11:     
 12:     if (conn)
 13:     {        
 14:         [[self navigationController] popViewControllerAnimated:YES];
 15:     }
 16:     else
 17:     {
 18:         //todo: add error message
 19:     }
 20: }

 

In the first line of this method, I retrieve the Facebook access token that is returned to me as a claim from Facebook after a successful login. The claims property of the WACloudAccessToken is a collection of all the claims that were passed through from the idP to the relying party application.

The rest of the lines are just used to create a POST request to Facebook. Any requests made to Facebook needs to include the access token (passed in as the access_token parameter). The message parameter is the actual text that will be posted to the feed, which must be URL-escaped.

If the post is successful, then I just navigate back to the details view (I didn’t any any error-handling in this example). A successful post to Facebook looks like this:

image

Conclusion

That’s really all to using ACS from an iPhone app using the Windows Azure Toolkit for iOS. Like I mentioned earlier, you can use ACS for your app’s authorization and authentication needs with other, multiple idPs. This is an especially low barrier-of-entry for apps that need to use Active Directory by taking advantage of ADFS through ACS.

I hope you enjoyed this post. If you have any questions, ask them in the comments section and I’ll try to answer them as best as I can. For the next part of the series, I will cover using Azure to send push notifications.