#.think.in
learn.create.enjoy

AdRotator: Json serialization

June 15, 2008 18:46 by tarn

This article is part of a series of posts about various aspects of writing web controls for ASP.Net using an ad rotator as an example. The AdRotator WebControl Example post has links to related posts and downloads.

The AdRotator needs to pass some data to the client side code so I use a Json serializer. I use the same class we use on the server side. The Json serializer converts an instance of it, or in our case a templated list of it, to a sting on JSON we can emit in the output. Json is JavaScript Object Notation and literally describes an object in Javascript that we can use in our client side Javascript code.

The object is very simple and only contains three strings and constructors. I have removed some of the attributes described in other articles as they are not relevant in this context.

public class ImageItem
{
    public ImageItem()
        : this(string.Empty, string.Empty, string.Empty)
    {
    }

    public ImageItem(string linkUrl, string imageUrl, string displayTime)
    {
        LinkUrl = linkUrl;
        ImageUrl = imageUrl;
        DisplayTime = displayTime;
    }

    public string LinkUrl { get; set; }
    public string ImageUrl { get; set; }
    public string DisplayTime { get; set; }
}

 

The AdRotator has a public property Images that is List of the ImageItem type above.

public List<ImageItem> Images;

 

During the RenderContents event of the AdRotator we can serialize this list into a string of Json.

JavaScriptSerializer serializer = new JavaScriptSerializer(); 
string json = serializer.Serialize(Images); 
 

The Json will look something like this.

[{"ImageUrl":"Images/Winter.jpg","LinkUrl":"#","DisplayTime":"1000"},
{"ImageUrl":"Images/Sunset.jpg","LinkUrl":"#","DisplayTime":"4000"}]

The following script and corresponding output will hopefully demonstrate how we can use the Json on the client side as data.

var imageList = [{"ImageUrl":"Images/Winter.jpg","LinkUrl":"#","DisplayTime":"1000"},
                 {"ImageUrl":"Images/Sunset.jpg","LinkUrl":"#","DisplayTime":"4000"}];

for(var i=0; i<imageList.length; i++)
{
    document.writeln(imageList[0].ImageUrl);
}

Output:

Images/Winter.jpg 
Images/Winter.jpg

 

Well that's all the information I'm going to include in this article. I'd like to go further into how the Json is used in the AdRotator but I've rambled on long enough. I think there is enough here to see that Json is a pretty cool language for communicating data between the server and client side Javascript.

I should also note that the JavaScriptSerializer is marked as depreciated and points towards the DataContractJsonSerializer. I briefly tried to get this working, but I couldn't seem to find the object in my system assemblies. To read more about that, check out DataContractJsonSerializer in .NET 3.5 that discusses using the DataContractJsonSerializer.

I hope you've found the article interesting, if you have you might be interested in reading more article about the AdRotator example or you might want to download and checkout the example project.


AdRotator: Client side code

June 15, 2008 18:23 by tarn

This article is part of a series of posts about various aspects of writing web controls for ASP.Net using an ad rotator as an example. The AdRotator WebControl Example post has links to related posts and downloads.

The Prototype

I wanted the client side code to be as object orientated as possible.  I implemented the behaviour of our AdRotator as  a prototyped Javascript object, equivalent to a class definition in other OO languages. This means every instance of the AdRotator on a page only needs to be an instance of the ad rotator prototype.

I create the anchor and image elements on the fly. I need the client side object to know about these elements to change them when the image changes. I could have created them in the server-side and passed their ids to find them in the DOM, or found them by looking through our containers child controls. In the end creating them on client side was just slightly easier.

The images parameter is an array of objects that have ImageUrl, LinkUrl and DisplayTime properties. I pass it in as Json (Javascript object notion) that I generated on the server using a Json serializer. You'll see the Json later in this article, and I've also added an article about generating Json script on the server side.

You notice the strange way setTimeout is called in the RotateAd function. It is all about Javascript scope and is far to big an issue to go into here. All I will say is that if I had used "this" instead on the "thisObject" which is set to "this" anyway, it might not point to this instance of this class, it might actually point to the document, window or whatever the current "this" actually is when the timeout event occurs.

function AdRotator(id, ads, height, width)
{
   this.id = id;
   this.ads = ads;
   this.index = 0;
   this.container = document.getElementById(id);

   this.anchorElement = document.createElement('a');
   this.imageElement = document.createElement('img');
   this.imageElement.setAttribute('height', height);   
   this.imageElement.setAttribute('width', height);
   this.anchorElement.appendChild(this.imageElement);
   this.container.appendChild(this.anchorElement);
   this.RotateAd();
}

AdRotator.prototype.RotateAd = function()
{
    var currentAd = this.NextAd();
    this.imageElement.setAttribute('src', currentAd.ImageUrl);
    this.anchorElement.setAttribute('href', currentAd.LinkUrl);
    var thisObject = this;
    setTimeout(function() { thisObject.RotateAd(); }, currentAd.DisplayTime);
}

AdRotator.prototype.NextAd = function()
{
    var ad = this.ads[this.index];
    this.index ++;
    if (this.index == this.ads.length) this.index = 0;
    return ad;
}

 

The Instance

For each instance of the ad rotator we simply use this script. You'll immediately notice that the code is filled with place holders. I replace these placed holders on the server-side before I inject it into the output. I'll describe these in more detail and finally I'll include the source of a rendered page to see this as the browser sees.

You might also notice that we are not actually assigning this object to anything. Hopefully because it will always be referenced by a setTimeout event it will always stay in scope. If I ever do have any problem with this I could easily create and array in the definition and push each instance into the array.

(new AdRotator('$ElementId', $Images, $Height, $Width));

 

The $ElementId placeholder is replaced with server control the server controls ClientId property. This means we can reference the DOM object (a span element) that the server outputs as a container for the control. The ClientId property is very importing when creating elements on the server and interacting with them on the client side. Often elements are not output with the ID of the server control. One of the reasons is that its possible in ASP.Net to have two control with the same ID in different placeholders. Or the same ID in a master page and in the content page. I won't go into detail about how this naming works, but its pretty clear when you view the source of the pages rendered by an ASP.Net server. It is a string as it's used by definition to find an element with the getElementById function.

The $Images place holder is replaced with Json. Effectively a Javascript object describing an object which is a an array of objects containing ImageUrl, LinkUrl and DisplayTime properties. I have written an article about how this Json is generated on the server side.

The $Height and $Width place holders are replaced by the corresponding values on the AdRotator server control.

An example of how this script is actually output by the server should hopefully demonstrates how this client side script actually works, and hopefully how it works for multiple controls.

<script type="text/javascript">
(new AdRotator('ctl00_MainContentPlaceHolder_rotator1', 
               [{"ImageUrl":"Images/Winter.jpg","LinkUrl":"Winter.aspx","DisplayTime":"1000"},
                {"ImageUrl":"Images/Sunset.jpg","LinkUrl":"Sunset.aspxd","DisplayTime":"4000"}],
                200, 200))
</script>

 

This is just one article in a series describing various aspects of writing ASP.Net server side controls. You can download the example code or assembly and see how it works.


AdRotator WebControl Example

June 15, 2008 18:01 by tarn

I didn't really actually want to write another ad rotator, but I did think it would be a good example control to implement. It has the scope to cover some aspects of writing web controls I wanted to learn more about and discuss. I decided to build an ASP.Net web control that cycles through a list of images on the client side. There are a few areas I want to discuss.

I wanted the control completely encapsulated within an assembly. So all you'd need to use the control would be a copy of the assembly. To do this I embedded some resources in the assembly and read them out at runtime. I discuss this in the article.

I wanted the control to be able to be created completely declaratively, and I thought providing the sort of intellisense you get when using standard ASP.Net controls would be nice.

I wanted the server-side control to inject Javascript into the output. I wanted the control to be smart enough to only output the Javascript prototype, or class definition once, even if there were multiple controls on the page. I wanted the client side code to be as object orientated as possible. 

You can download the source code which includes an example website in the solution.

I would like to add a post about supporting difference storage mechanisms and using the control, but I have other projects demanding my attention. Hopefully I'll get back to it sometime.

I Hope you've found some of these articles useful or interesting. I'll keep and eye on the comments, contribute to further discussion, and update the posts where errors or omissions are noted.

Cheers