Live Framework SDK – Inviting Others

Following on from this previous post, the WPF and Silverlight code that I’ve been running tries to access a MeshObject ( containing a DataFeed of photos ) that the code itself creates at initialisation time.

What I wasn’t sure about at all was how that’d work if I wanted to make the same data available to another person altogether.

As it stands, my WPF code runs up and does;

  1. Check local mesh for “photos” MeshObject.
  2. If not present, check cloud mesh for the same.
  3. If not present, create it.

If I want to share my photos with lots of other users of the same application then is that what I want? All my users will end up with their own MeshObjects with their own photos and none of them will ever see each other.

So…I set about trying to figure out what the “shared data story” is.

There’s a sample in the walkthroughs called MeshageBoard ( no, really 🙂 ) which helps quite a lot with this in that it shows the way in which one user can send invitations to another.

In order to experiment with this, I decided that it was time to grab myself a secondary Live ID so that I could log in to Live more than once and to run that Live ID through the registration process for the Live Framework CTP ( luckily, I found that I had a little card at the bottom of my desk drawer from PDC with 2 Live Framework invitation codes on it so that I could get an invitation for my second account ).

What the sample taught me is about inviting users “to” a MeshObject. I wrote a bit of code to play with this – just a simple console application that exercises a few API’s;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.LiveFX.Client;
using System.Net;
using Microsoft.LiveFX.ResourceModel;

class Program
{
  static void Main(string[] args)
  {
    while (!exit)
    {
      ReadAndExecuteOption();
    }
  }
  static void ReadAndExecuteOption()
  {
    var options = new[] {
      new { OptionName = "loginLocal", OptionFn = new Action( () => OnLoginLocal() ) },
      new { OptionName = "loginCloud", OptionFn = new Action( () => OnLoginCloud() ) },
      new { OptionName = "createMo", OptionFn = new Action( () => OnCreate() ) },
      new { OptionName = "contacts", OptionFn = new Action( () => OnContacts() ) },
      new { OptionName = "exit", OptionFn = new Action( () => OnExit() ) },
      new { OptionName = "displayMo", OptionFn = new Action( () => OnDisplay() )},
      new { OptionName = "invite", OptionFn = new Action( () => OnInvite() ) }
    };

    Console.Write("Options:");

    foreach (var option in options)
    {
      Console.Write("[{0}] ", option.OptionName);
    }
    Console.WriteLine();

    string input = Console.ReadLine();

    var opt = options.Where(
      o => string.Compare(input, o.OptionName, true) == 0).SingleOrDefault();

    if (opt != null)
    {
      try
      {
        opt.OptionFn();
      }
      catch (Exception ex)
      {
        Console.WriteLine("Sorry, that didn't work - message is \n[{0}]\n",
          ex.Message);
      }
    }
  }
  static void OnCreate()
  {
    Console.WriteLine("Enter name of mesh object to create");
    string name = Console.ReadLine();
    MeshObject mo = new MeshObject(name);
    loe.Mesh.MeshObjects.Add(ref mo);
  }
  static void OnLoginLocal()
  {
    loe = new LiveOperatingEnvironment();
    loe.ConnectLocal();
  }
  static void OnLoginCloud()
  {
    Console.Write("Username:");
    string userName = Console.ReadLine();
    Console.Write("Password:");
    string password = Console.ReadLine();
    loe = new LiveOperatingEnvironment();
    loe.Connect(new NetworkCredential(userName, password));
  }
  static void OnContacts()
  {
    Console.WriteLine("Contacts...");
    foreach (Contact c in loe.Contacts.Entries)
    {
      Console.WriteLine("\tContact: Display Name [{0}] LiveId [{1}]",
        c.Resource.DisplayName,
        c.Resource.Emails.Count == 0 ? "None" : c.Resource.WindowsLiveId);
    }
  }
  static void OnExit()
  {
    exit = true;
  }
  static void OnDisplay()
  {
    Console.WriteLine("MeshObjects...");

    loe.Mesh.MeshObjects.Load();

    foreach (MeshObject mo in loe.Mesh.MeshObjects.Entries)
    {
      Console.WriteLine("\tMesh Object: Title [{0}]", mo.Resource.Title);
    }
  }
  static void OnInvite()
  {
    Console.Write("Mesh Object Name:");
    string meshObjectName = Console.ReadLine();
    Console.Write("Live Id to Invite:");
    string liveId = Console.ReadLine();

    MeshObject mo = loe.Mesh.MeshObjects.Entries.Where(
      m => m.Resource.Title == meshObjectName).Single();

    Invitation invitation = new Invitation();
    invitation.Expires = DateTimeOffset.UtcNow.Add(new TimeSpan(1, 0, 0));
    invitation.Email = string.Format("Would you like to join mesh object {0}",
      meshObjectName);    

    Member member = new Member(liveId);
    member.Resource.PendingInvitation = invitation;
    member.Resource.Role = RoleType.Reader;

    mo.Members.Add(ref member);

    mo.Update();
  }
  static LiveOperatingEnvironment loe;
  static bool exit;
}

and with that in place I can go and run it…

image image

The console window on the left shows me logging in to the cloud as mtaulty@hotmail.com and then creating a MeshObject called “TestObject”.

The console window on the right shows me logging in to the cloud as mtaulty@live.co.uk and first displaying that I only have one MeshObject called “Foo”.

In the console window on the left, I then go and invite mtaulty@live.co.uk into that MeshObject called “TestObject”.

Then ( in the background ) I (mtaulty@live.co.uk) go and accept the email invitation to the object called “TestObject” and so the next time I display my MeshObjects in the right hand window, that new object has shown up in my Mesh.

Very cool – it surprised me as to how easy this was. From the code above, I only gave the invited Member a role of Reader but I could have given them more control.

This makes me realise that I need to re-write my sketchy photo sharing “application” … 🙂