Sharing Data Between Users in the Live Framework API

This is a pretty basic post on inviting other users to access a Mesh Object and the data feeds attached to it. Even though Mike Taulty has  posted on invitations here and here I felt it was worth putting this up to remind myself how invitations work.

The central idea of the Live Mesh is the ability to synchronize data between devices and users in a secure manner. Data synchronization between devices is enabled through the use of device mappings while data sharing between users is enabled through the invitation mechanism. The owner of a Mesh Object who wants to provide access to its data feeds to someone else must invite them to subscribe with a particular role, for example reader or writer. The invitation can be achieved programmatically using the Live Framework API which causes an email to be sent to the other user who is redirected to the Live Desktop to accept or reject the invitation. The invitation process always has this out-of-band step of using email – there is no mechanism to accept an invitation using software or in any automated way. The email is sent almost immediately and there is essentially no delay in the request other than the gating processes of logging into email and the Live Desktop.

Classes Used With Invitations

The Member class is declared:

public sealed class Member : LiveItem<MemberResource> {
    // Constructors
    public Member(String email);
    public Member(String email, RoleType role, Boolean isOwner);
    public Member();
    public Member(MemberResource resource);

    // Properties
    public LiveItemCollection<Profile,ProfileResource> Profiles { get; }
}

The interesting property with regard to invitations is the base class Resource of type MemberResource declared as:

public sealed class MemberResource : Resource {
    // Constructors
    public MemberResource(String email);
    public MemberResource(SyndicationItem source);
    public MemberResource();
    public MemberResource(String email, RoleType role, Boolean isOwner);

    // Properties
    public String Email { get; set; }
    public Boolean InvitationAccepted { get; }
    public Boolean IsOwner { get; }
    public Invitation PendingInvitation { get; set; }
    public Uri ProfilesLink { get; }
    public RoleType Role { get; set; }

    // Methods
    public static ResourceDescription GetResourceDescription();

    // Implemented Interfaces and Overridden Members
    protected override void SaveSyndicationLinks(Collection<SyndicationLink> links);
    protected override Boolean LoadSyndicationLink(SyndicationLink link);
}

The Email property identifies the user to whom the invitation should be sent. The invited user will be asked to sign in to the Live Desktop or create an account prior to signing in. During the Live Framework CTP I suspect this will fail if the user is not authorized to access the CTP. PendingInvitation contains information used in issuing the invitation. RoleType provides rudimentary role-based access control to the invited user’s access to the Mesh Object which is the object of the invitation. The RoleType can take on the following values:

Author – appears to be the same as Full
Full – create, read, update, delete
Reader – read
Writer – appears to be the same as Full

There are a couple of problems with the declaration of the MemberResource class:

  • The last constructor sets the IsOwner property which is only readable as a property.
  • PendingInvitation, which is settable as a property, is not settable as part of the last constructor which sets the other two settable properties.

I believe the last constructor should be declared as:

    public MemberResource(String email, RoleType role, Invitation pendingInvitation);

because that would be usable immediately in issuing invitations to other users. If IsOwner is settable then it should be settable as a property as well as in the constructor.

The Invitation class is declared:

public sealed class Invitation {
    // Constructors
    public Invitation();

    // Properties
    public Uri AcceptanceLink { get; }
    public Uri AcceptInvitationLink { get; }
    public Boolean AllowAnyoneToAccept { get; set; }
    public Uri DeclineInvitationLink { get; }
    public String Email { get; set; }
    public DateTimeOffset Expires { get; set; }
    public String InvitedBy { get; }
    public String MeshObjectDescription { get; }
    public String MeshObjectName { get; }
    public String MeshObjectType { get; }
    public String Secret { get; }
    public Uri UserInterfaceLink { get; }
}

Most of the invitation properties are only gettable. It is not immediately obvious what is the purpose of AllowAnyoneToAccept. Expires is used to specify a time offset to a time when the invitation expires. The Email property contains a developer-defined text string inserted into the invitation email in addition to the standard invitation text inserted by the Live Mesh.

There is another issue with the declarations of the MemberResource and Invitation classes. They both contain a property named Email which in MemberResource is the actual email address to which the invitation is sent and in Invitation is a developer-defined text displayed as part of the invitation. This is an invitation for confusion. I believe Invitation.Email should be renamed something like Invitation.EmailText.

Mapped Devices

One issue that arises is that accepting an invitation to access a Mesh Object provides a user with access to it in the cloud. If the user wants to use the Mesh Object in the local LOE then it will have to be mapped to the local device. This does not happen as part of the invitation process so will have to be handled separately.

Example

The Live Framework API makes it very easy to invite users to access a Mesh Object. The following method is pretty close to the minimal code required:

public void InviteUserToAccessMeshObject( MeshObject meshObject)
{
    Invitation invitation = new Invitation();
    invitation.Expires = DateTimeOffset.UtcNow.AddDays(7);
    invitation.Email = String.Format("Would you like to access the Mesh Object named {0}", meshObject.Resource.Title);

    Member member = new Member();
    member.Resource.PendingInvitation = invitation;
    member.Resource.Role = RoleType.Reader;
    member.Resource.Email = "validCtpUser@live.com";

    meshObject.Members.Add(ref member);
    meshObject.Update();
}

This method causes an email invitation to be issued to the user identified as validCtpUser@live.com to gain read-only access to the Mesh Object passed as a parameter. The invitation will be valid for seven days from the time it is issued.

On accepting the invitation the user will be able to access the Mesh Object, indeed when viewed in the LiveFX Resource Browser it looks identical to any of the MeshObjects created by the user. Since security is performed at the Mesh Object level the user will be able to access all data feeds and their data entries attached to the Mesh Object. Since this user has read-only access to the Mesh Object any attempt to update it will cause a Microsoft.LiveFX.Client.LiveOperationException to be thrown with a message of "Unauthorized." The user would be able to update the Mesh Object had the invitation been issued with an appropriate RoleType.

Technorati Tags: ,

About Neil Mackenzie

Cloud Solutions Architect. Microsoft
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s