Page view counter

Jesse Liberty - Silverlight Geek

More Signal Less Noise

The Great Asynchronous Learning Experiment - Day 6

[Updated 11:50pm 9/11 to make this a bit more readable]

 As you may know, I've become very interested in the idea of hypervideo. In my first HDI video on HyperVideo I hard coded the links to the markers in the movie but I talked about trying again, with decoupled links.

My original idea was to put the link-to-marker association in a database or an XML file, but Tim Heuer, suggested JSON (smart guy, that Tim!).

So, how do you do this with JSON?  This isn't finalized yet, but to give you a quick idea of how easy such a thing can be, try this: fire up Visual Studio 2008 (Beta 2) and create a new Web application. Place a rather large text box in your aspx page (I made mine 600 x 400); set it to multi-line, read only and set the wrap to true.

In your App_Code you'll add your classes in a file named JSON.cs.

Our long term goal is to be able to pass the movie name to a web service and  get back the list of markers and the list of links for those markers. In fact, we don't want to have to know the name of the web service, so we'll embed the name of the web service right in the first marker in the movie.

Our first class is Movie, which contains just three members: the name of the movie:, the URI of the web service that knows about that movie:, and the list of Marker objects:


[Serializable()]
[XmlRoot("Movie")]
public class Movie
{
    private string movieTitle;
    private string movieURI;
    private List<Marker> movieMarkers;

Notice that the class requires the attribute Serializable (we're going to serialize to JSON) and we mark the class with the XMLRoot attribute

We go on to mark each property with the XMLElement attribute:


[XmlElement("Title")]
public string Title
{
    get { return movieTitle; }
    set { movieTitle = value; }
}

[XmlElement("URI")]
public string URI
{
    get { return movieURI; }
    set { movieURI = value; }
}

[XmlElement("Markers")]
public List Markers
{
    get { return movieMarkers; }
    set { movieMarkers = value; }
}

Finally, we create the ToJson() method which will do the actual serialization...


public string ToJson()
{
    System.Web.Script.Serialization.JavaScriptSerializer js = 
        new System.Web.Script.Serialization.JavaScriptSerializer();
    return js.Serialize(this);
}

 The MarkerLink class has two member variables: linkURI and linkText that will be filled with the URI and text to display at a given marker.

[Serializable()]
public class MarkerLink
{
    private string linkURI;
    private string linkText;

    [XmlElement("LinkURI")]
    public string LinkURI
    {
        get { return linkURI; }
        set { linkURI = value; }
    }
   
    [XmlElement("Text")]
    public string Text
    {
        get { return linkText; }
        set { linkText = value; }
    }
}

The Marker class represents the information for a given marker at a particular location in a movie. The name of the marker is used to refer to it in code. Its type, text and time are embedded in the movie itself. The final member is a list of MarkerLink objects, allowing each Marker to have zero or more links associated with that marker.

These markers are then rolled up into the Movie class whose final member is a list of Markers.

[Serializable()]
public class Marker
{
    private string markerName;
    private string markerType;
    private string markerText;
    private string markerTime;
    private List<MarkerLink> links;


    [XmlElement("Name")]
    public string Name
    {
        get { return markerName; }
        set { markerName = value; }
    }

    [XmlElement("Type")]
    public string Type
    {
        get { return markerType; }
        set { markerType = value; }
    }

    [XmlElement("Text")]
    public string Text
    {
        get { return markerText; }
        set { markerText = value; }
    }

    [XmlElement("Time")]
    public string Time
    {
        get { return markerTime; }
        set { markerTime = value; }
    }

    [XmlElement("Links")]
    public List Links
    {
        get { return links; }
        set { links = value; }
    }

With this in place, we're ready to rock and roll.  In the Page_Load method of default.aspx we instantiate a Movie object and set its Title and URI properties, and intialize its list of markers. We then, for the purpose of this demonstration,  populate the indices randomly and serialize all of this data into a JSON text string.

This is where you have to let your imagination run a little wild..... Imagine that when we are creating the links for the movie we start by embedding markers (say) every 30 seconds with no intrinsic meaning (e.g., Marker1, Marker2, Marker3). We then present a web page that the movie owner uses that lets the movie owner  fill in the movie name, and then add information for each marker, including zero or more links for that marker (e.g, for marker04 there are three links).  Once the movie owner presses SAVE all of the movie information (including the markers and their links) are serialized into JSON format and stored (perhaps in a SQL Server database).

Later, the user comes along to download the movie. The movie viewer (to be created) reads the first marker and makes contact with the web service whose URI is embedded in the movie, and provides the movie name (also embedded in the movie) What the viewr gets back  a JSON structure.

To make sure we've saved all this information correctly we can format and display the JSON string in the text box in our ASXM file. I took a brute force approach to making it look readable,


     // place in text box
     SerializedText.Text = FormatJson(mov.ToJson());

}

private string FormatJson(string p)
{
     int level = 1;
     string output = string.Empty;
     foreach (char c in p)
     {
         output += FixJsonChar(c, ref level);
     }
     return output;
}
private string FixJsonChar(char c, ref int level)
{
     if (c == '{')
     {
         string output = string.Empty;
         output += "\n";
         ++level;
         for (int i = 0; i < level; i++)
         {
             output += "  ";
         }
         output += c;
         return output;
     }
     if (c == '}')
     {
         --level;
         return c.ToString();
     }
     if (c == '[' || c == ']')
     {
         string output = string.Empty;
         output += "\n";
         for (int i = 0; i < level; i++)
         {
             output += "  ";
         }
         output += c;
         return output;
     }
     if (c == ']')
     {
         string output = string.Empty;
         output += "\n";
         for (int i = 0; i < level; i++)
         {
             output += "  ";
         }
         output += c;
         return output;
     }

     if (c == ',')
     {
         string output = string.Empty;
         output += c;
         output += "\n";
         for (int i = 0; i < level; i++)
         {
             output += "  ";
         }

         return output;
     }
       
    
     else
     {
         return c.ToString();
     }

}

(NB: all the clever JSON work was done by Tim, but all the hacking was done by me, so shout at me.)

What you get back is very cool...


  {"Title":"All About Silverlight",
    "URI":"http://mymovieurl.com/AllAboutSL.wmv",
    "Markers":
    [
      {"Name":"Marker 0",
      "Type":"Uri",
      "Text":"This is marker 0",
      "Time":"00:00",
      "Links":
      [
        {"LinkURI":"http://0.resource.com",
        "Text":"Visit Resource 0"},
      
        {"LinkURI":"http://1.resource.com",
        "Text":"Visit Resource 1"}
      ]},
    
      {"Name":"Marker 1",
      "Type":"Uri",
      "Text":"This is marker 1",
      "Time":"00:01",
      "Links":
      [
        {"LinkURI":"http://0.resource.com",
        "Text":"Visit Resource 0"},
      
        {"LinkURI":"http://1.resource.com",
        "Text":"Visit Resource 1"}
      ]},
    
      {"Name":"Marker 2",
      "Type":"Uri",
      "Text":"This is marker 2",
      "Time":"00:02",
      "Links":
      [
        {"LinkURI":"http://0.resource.com",
        "Text":"Visit Resource 0"},
      
        {"LinkURI":"http://1.resource.com",
        "Text":"Visit Resource 1"}
      ]}
    ]}

Yes, there are other ways to do this, but this is quick, easy, human readable, works and plays well with Ajax and gives us tremendous flexibility.

 

-j

Comments

The Great Asynchronous Learning Experiment - Day 6 - Jesse Liberty - Silverlight Geek said:

Pingback from  The Great Asynchronous Learning Experiment - Day 6 - Jesse Liberty - Silverlight Geek

# September 10, 2007 4:23 PM

Test said:

Okay, today I merge my two personalities: the learner and the Silverlight Geek . It was making me crazy

# September 10, 2007 5:58 PM

jesseliberty said:

Doug Nelson sent me this email, but for some reason couldn't post to the blog...

Just read you latest post.  Great series of articles, I am enjoying them very much.  I have been playing with Silverlight a bit.

I would also like to point out that the Asp.Net Ajax framework already provides a JSON converter class.

asp.net/.../N_System_Web_Script_Serialization.aspx

------

While I knew about the built-in support for JSON, the link is very valuable and turns out to be tricky to find. Thanks Doug!!

# September 11, 2007 10:03 PM

Blogs said:

in my previous sample i talked about creating custom expression encoder templates . good times. also

# September 14, 2007 2:26 PM

bnkausik said:

fully functional hypervideo browser and authoring service....www.asterpix.com/console

# October 20, 2007 12:14 AM