Further into the Live Framework – Data Entries

Well on Monday I blogged about getting started with some of the Live Framework Resource Model within the developers Mesh, I have asked around but it seems that this feed is currently unavailable with the normal beta (www.mesh.com).

One resource I did find on the MSDN library for understanding the objects in this model is in the image below:

 LiveOperatingEnvironment

https://msdn.microsoft.com/en-gb/library/dd137022.aspx

Starting at the top, the Service Endpoint would be the Live Operating Environment object which allows a connection to the Cloud (or as I later found out to your local cloud by doing a LocalConnect, to do this download the dev mesh client from https://developer.mesh-ctp.com/.

A good video explaining this is by Dan Fernandez on channel 9 at around 4:45:

https://channel9.msdn.com/posts/Dan/Ori-Amiga-Programming-the-Mesh

Also on some more on these data entries and media resources by Jared Bienz at 2:13 with a great example of a mesh application (rather than client mesh application):

https://channel9.msdn.com/posts/jbienz/Live-Framework-and-Always-Available-Social-Applications/

So the level we were at in the last blog post was from Service Endpoint (The Live Environment), –> Mesh –> Mesh Objects –> Data Feeds, so under the Data Feeds we will be looking at Data Entries, which will be the content of the MeshageBoards.

Some other useful items to note in here are;

that this diagram is not quite complete… If we dive under Data Entries, we will find Media Resource (one level down), if you create a mesh folder then upload an image/music/video file then navigate to that object using the Live Framework Resource Browser (packaged with tools in the SDK) through

https://user-ctp.windows.net/V0.1/Mesh/MeshObjects/\[identifier\]/DataFeeds/\[identifier\]/Entries

or by navigating through Cloud Live Operating Environment –> Mesh –> Mesh Objects –> find the folder (probably with summary <summary type="text">Live Mesh folder to synchronize and share data.</summary>) choosing Data Feeds –> DataEntries –> find your media file entry (image/music/video) and look under <Properties>, <MediaResource>, <MediaType> you will see that it is probably a stream or octet-stream… Clicking on the first <link> within the entry with rel=”edit-media” you will see the representation of that file in binary (ascii or unicode encoded).  This could be extremely useful when trying to stream files, and possibly even between devices (although I have not tried this yet…).

Another note is that there are 2 news feeds, one for the entire mesh and one for the individual objects themselves.

I’ll leave some other investigation of objects down to you, but there are some very useful resources, and I believe that most of these Entries are LINQ query enabled.

 

Back to the Walkthrough

So I left off last time allowing you to connect to the mesh, create a MeshageBoard, list all the MeshageBoards you have and remove a Meshageboard.

Firstly I noticed a couple of bugs;

First I noticed that the methods wouldn’t return and keep adding to the call stack so I fixed this by changing in Program.cs the HandleUserInput method, and so the GetOut method:

 private static void HandleUserInput()
{
   while (true)
   {
      Console.WriteLine("");
      Console.WriteLine("1: Create a New MeshageBoard.");
      Console.WriteLine("2: List All MeshageBoards.");
      Console.WriteLine("3: Make a Posting.");
      Console.WriteLine("4: List All Postings for a MeshageBoard.");
      Console.WriteLine("5: Invite Members to a MeshageBoard.");
      Console.WriteLine("6: Reset the demo.");
      Console.WriteLine("7: Remove a MeshageBoard");
      Console.WriteLine("8: Exit the program.");
      Console.Write(">");
      string input = Console.ReadLine();
      switch (input)
      {
         case "1":
            CreateNewMeshageBoard();
            break;
         case "2":
            ListAllMeshageBoards();
            break;
         case "3":
            MakeAPosting();
            break;
         case "4":
            PrintMessages();
            break;
         case "5":
            InviteMembers();
            break;
         case "6":
            ResetAll();
            break;
         case "7":
            RemoveMeshageBoard();
            break;
         case "8":
            GetOut();
            break;
         default:
            Console.WriteLine("Please enter a valid value.");
            break;
      }
   }
}
// Provide a way to exit the program.

private static void GetOut()
{
   Console.WriteLine("Press any key to exit.");
   ConsoleKeyInfo cki = Console.ReadKey(true);
   if (cki != null)
      Environment.Exit(0);
}

Then remove all the HandleUserInput calls except the one in Main, I have listed the methods below, along with a refactoring of the method which allows the user to select a board (explained in the walkthrough below)

 private static void CreateNewMeshageBoard()
{
   Start:
      Console.Write("Please enter the name for your MeshageBoard: ");
      string input = Console.ReadLine();
      MeshageBoard.CreateMeshageBoard(env, input);
      Console.Write("Would you like to create another (y/n)?\r\n> ");
      string yesOrNo = Console.ReadLine();
      if (yesOrNo.ToLower() == "y")
         goto Start;
      else
         return; ;
}
private static void ListAllMeshageBoards()
{
   ObservableCollection<MeshObjectResource> meshBoardList = new ObservableCollection<MeshObjectResource>();
   meshBoardList = MeshageBoard.GetAllMeshageBoard(env);
   foreach (MeshObjectResource resource in meshBoardList)
   {
      Console.WriteLine(resource.Title);
   }
}
private static void RemoveMeshageBoard()
{
   string selectedTitle = UserSelectionBoard();
   if (selectedTitle != null)
   {
      MeshageBoard.RemoveMeshageBoard(env, selectedTitle);
   }
}
private static ObservableCollection<MeshObjectResource> GetListOfBoards()
{
   ObservableCollection<MeshObjectResource> meshBoardList = new ObservableCollection<MeshObjectResource>();
   meshBoardList = MeshageBoard.GetAllMeshageBoard(env);
   int i = 0;
   Console.WriteLine("Choose a MeshageBoard:");
   foreach (MeshObjectResource resource in meshBoardList)
   {
      Console.WriteLine(i + ": " + resource.Title);
      i++;
   }
   return meshBoardList;
}
// Ask the user to select a specific board with exception handling

private static string UserSelectionBoard()
{
Selection:
   ObservableCollection<MeshObjectResource> meshBoardList = GetListOfBoards();
   string input = Console.ReadLine();
   string selectedTitle = null;
   try
   {
      int sel = Int32.Parse(input);
      selectedTitle = meshBoardList[sel].Title;
   }
   catch (FormatException)
   {
      Console.Write("Please make your selection using the numbers proceeding the title\r\n\r\nTry Again (y/n)?\r\n>");
      string yesOrNo = Console.ReadLine();
      if (yesOrNo.ToLower() == "y")
      {
         goto Selection;
      }
      else
      {
         return null;
      }
   }
   catch (ArgumentOutOfRangeException)
   {
      Console.Write("Please select a number from the range given\r\n\r\nTry Again (y/n)?\r\n>");
      string yesOrNo = Console.ReadLine();
      if (yesOrNo.ToLower() == "y")
      {
         goto Selection;
      }
      else
      {
         return null;
      }
   }
   return selectedTitle;
}

I have also refactored the user selection of boards out into the function UserSelectedBoard.

I blogged about not hardcoding the user’s address in the resources so I have modified Main to:

 static void Main(string[] args)
{
   Start:
   LiveItemAccessOptions miao = new LiveItemAccessOptions(true);
   try
   {
      string appId = Resources.AppId;
      Console.Write("Please enter your Email Passport:\r\ne.g. someone@hotmail.com\r\n>");
      string address = Console.ReadLine();
      Console.Write("Please enter your password:\r\n>");
      string password = GetPassword();
      Console.Clear();
      Console.WriteLine("Connecting to the Mesh...");
      foreach (string line in meshImage)
      {
         Console.WriteLine(line);
      }
      Uri cloudURL = new Uri(Resources.CloudURI);
      NetworkCredential creds = new NetworkCredential(address, password);
      env = new LiveOperatingEnvironment();
      env.Connect(creds);
      Console.Clear();
      Console.Write("You are now connected. \r\n");
   }
   catch (Exception ex)
   {
      Console.Clear();
      Console.WriteLine("Caught exception trying to connect: " + ex.Message);
      Console.Write("Would you like to re-enter your password? (y/n)\r\n>");
      string yesOrNo = Console.ReadLine();
      if (yesOrNo.ToLower() == "y")
         goto Start;
      else
      {
         Console.WriteLine("Press any key to exit");
         Console.Read();
         return;
      }
   }
   HandleUserInput();
}

 

Creating posting on MeshageBoards

So now we have our MeshageBoards, and we want to write a message on our board. This is going to use one level lower on the diagram (under the Data Feeds) the Data Entries.

First we want to be able to list our boards in a nice way so that the user can select which board they want to add their message to.  In MeshageBoard.cs add a method to select a board (also used above in the remove board function, better than the user typing in the name).

 public static MeshObject GetMeshageBoardMeshObject(LiveOperatingEnvironment env, string BoardTitle)
{
   if (!env.Mesh.MeshObjects.IsLoaded)
      env.Mesh.MeshObjects.Load();
   MeshObject messageBoard = (from i in env.Mesh.MeshObjects.Entries
                        where
                           String.Equals(i.Resource.Type, "MeshageBoard")
                           && String.Equals(i.Resource.Title, BoardTitle)
                        select i).FirstOrDefault<MeshObject>();
   return messageBoard;
}

Now we want a class to manage the content (adding and listing the messages in the board) so create a new class (MeshageBoardContent.cs) in the MeshageBoard_Classes class library we created in the previous blog: https://blogs.msdn.com/davethompson/archive/2009/01/26/introduction-to-the-live-framework.aspx

Add the using directives for the Live Framework:

 using Microsoft.LiveFX.Client;
using Microsoft.LiveFX.ResourceModel;

using System.Collections.ObjectModel;

Add the public and static modifiers to the class

 public static class MeshageBoardContent

Then write the method for doing the work…

 public static void PostToMeshageBoardContent(LiveOperatingEnvironment env, string PostText, string BoardTitle)
{
   MeshObject messageBoard = MeshageBoard.GetMeshageBoardMeshObject(env, BoardTitle);
   if (messageBoard == null)
   {
      throw new Exception("Mesh Object cannot be null");
   }
   if (!messageBoard.DataFeeds.IsLoaded)
   {
      messageBoard.DataFeeds.Load();
   }
   DataFeed boardFeed = (from i in messageBoard.DataFeeds.Entries
                    where string.Equals(i.Resource.Type, "MeshageBoard_DataFeed")
                    select i).FirstOrDefault<DataFeed>();
   DataEntry entry = new DataEntry(PostText);
   boardFeed.DataEntries.Add(ref entry);
   messageBoard.Update();
}

This is just getting the MeshageBoard we want to write to, loading the datafeeds of that MeshageBoard (if not already loaded), then finding the DataFeed for the meshage board (though there should only be one data feed) create a simple DataEntry (just with a string) and add it to the feed.

There is an overload on the constructor of DataEntry which takes a DataEntryResource which in turn has a MediaResource (as talked about in the MeshChat video (https://channel9.msdn.com/posts/jbienz/Live-Framework-and-Always-Available-Social-Applications/)

Next we write the helper methods in Program.cs (one of which, GetListOfBoards, has been defined above, but I have copied it below also:

 private static ObservableCollection<MeshObjectResource> GetListOfBoards()
{
   ObservableCollection<MeshObjectResource> meshBoardList = new ObservableCollection<MeshObjectResource>();
   meshBoardList = MeshageBoard.GetAllMeshageBoard(env);
   int i = 0;
   Console.WriteLine("Choose a MeshageBoard:");
   foreach (MeshObjectResource resource in meshBoardList)
   {
      Console.WriteLine(i + ": " + resource.Title);
      i++;
   }
   return meshBoardList;
}
private static void MakeAPosting()
{
   string selectedTitle = UserSelectionBoard();
   if (selectedTitle != null)
   {
      Console.WriteLine(selectedTitle + " was selected.");
   Start:
      Console.Write("Enter your message.\r\n>");
      string postingText = Console.ReadLine();
      MeshageBoardContent.PostToMeshageBoardContent(env, postingText, selectedTitle);
      Console.Write("Would you like to create another (y/n)?\r\n>");
      string yesOrNo = Console.ReadLine();
      if (yesOrNo.ToLower() == "y")
         goto Start;
   }
}

Simply uncomment the case “3” HandleUserInput method for MakeAPosting:

 private static void HandleUserInput()
{
   while (true)
   {
      Console.WriteLine("");
      Console.WriteLine("1: Create a New MeshageBoard.");
      Console.WriteLine("2: List All MeshageBoards.");
      Console.WriteLine("3: Make a Posting.");
      Console.WriteLine("4: List All Postings for a MeshageBoard.");
      Console.WriteLine("5: Invite Members to a MeshageBoard.");
      Console.WriteLine("6: Reset the demo.");
      Console.WriteLine("7: Remove a MeshageBoard");
      Console.WriteLine("8: Exit the program.");
      Console.Write(">");
      string input = Console.ReadLine();
      switch (input)
      {
         case "1":
            CreateNewMeshageBoard();
            break;
         case "2":
            ListAllMeshageBoards();
            break;
         case "3":
            MakeAPosting();
            break;
         case "4":
            PrintMessages();
            break;
         case "5":
            InviteMembers();
            break;
         case "6":
            ResetAll();
            break;
         case "7":
            RemoveMeshageBoard();
            break;
         case "8":
            GetOut();
            break;
         default:
            Console.WriteLine("Please enter a valid value.");
            break;
      }
   }
}

Now after running the program and creating a message on a board you can navigate to that board in the Resource Browser tool and you should see the entry added to the boards data feed.  Notice that unlike most files uploaded to the mesh (examine a folder object) it doesn’t have a media resource attached, so is simply the text entered.

Viewing Posts

Now we want to view our messages without having to look at the feed directly in the Resource Browser, so we can view it in our command window.

Back in our content class (MessageBoardContent.cs), we create a method to iterate over the entries and return them…

 public static ObservableCollection<DataEntryResource> GetAllMeshageBoardContent(LiveOperatingEnvironment env, string BoardTitle)
{
   ObservableCollection<DataEntryResource> listAllMeshageBoard = new ObservableCollection<DataEntryResource>();
   MeshObject messageBoard = MeshageBoard.GetMeshageBoardMeshObject(env, BoardTitle);
   if (messageBoard == null)
   {
      return listAllMeshageBoard;
   }
   if (!messageBoard.DataFeeds.IsLoaded)
   {
      messageBoard.DataFeeds.Load();
   }
   DataFeed boardFeed = (from i in messageBoard.DataFeeds.Entries
                    where string.Equals(i.Resource.Type, "MeshageBoard_DataFeed")
                    select i).FirstOrDefault<DataFeed>();
   if (!boardFeed.DataEntries.IsLoaded)
   {
      boardFeed.DataEntries.Load();
   }
   foreach (DataEntry entry in boardFeed.DataEntries.Entries)
   {
      listAllMeshageBoard.Add(entry.Resource);
   }
   return listAllMeshageBoard;
}

This does the same thing as our post method, only instead of posting a message we are receiving them.

Back in our Program.cs file add the method to call this

 public static void PrintMessages()
{
   string selectedTitle = UserSelectionBoard();
   ObservableCollection<DataEntryResource> content = MeshageBoardContent.GetAllMeshageBoardContent(env, selectedTitle);
   if (content.Count == 0)
   {
      Console.WriteLine("Sorry, there are no messages in this board to display.");
   }
   else
   {
      Console.WriteLine("Messages for MeshageBoard " + selectedTitle);
      foreach (DataEntryResource res in content)
      {
         Console.WriteLine(res.Title);
      }
   }
}

and finally uncomment the 4th case from HandleUserInput method (PrintMessages):

 private static void HandleUserInput()
{
   while (true)
   {
      Console.WriteLine("");
      Console.WriteLine("1: Create a New MeshageBoard.");
      Console.WriteLine("2: List All MeshageBoards.");
      Console.WriteLine("3: Make a Posting.");
      Console.WriteLine("4: List All Postings for a MeshageBoard.");
      Console.WriteLine("5: Invite Members to a MeshageBoard.");
      Console.WriteLine("6: Reset the demo.");
      Console.WriteLine("7: Remove a MeshageBoard");
      Console.WriteLine("8: Exit the program.");
      Console.Write(">");
      string input = Console.ReadLine();
      switch (input)
      {
         case "1":
            CreateNewMeshageBoard();
            break;
         case "2":
            ListAllMeshageBoards();
            break;
         case "3":
            MakeAPosting();
            break;
         case "4":
            PrintMessages();
            break;
         case "5":
            InviteMembers();
            break;
         case "6":
            ResetAll();
            break;
         case "7":
            RemoveMeshageBoard();
            break;
         case "8":
            GetOut();
            break;
         default:
            Console.WriteLine("Please enter a valid value.");
            break;
      }
   }
}

There you have it, you can now post messages and view them!

Just one section left on inviting users, and I’ll try to have a play around with MediaResources to find the gritty details :)

Have Fun…