How to send data from Javascript to Silverlight control to render charts

by Viper 31. July 2009 15:09

Download Demo Project

I have been discussing use of jQuery to send AJAX request to server to get some data every X number of seconds to get server time and calculate some latency numbers. Now it is time to add some color to it. The numbers that I am getting is great and provide some useful information. But having a visual of how these numbers are varying with time will enhance utility of these statistics. So I decided to add some charts to show these latency numbers are varying with time. In this article I am going to show how you can pass the data obtained from server using AJAX request to a Silverlight application hosted on the page. This silverlight application uses charting control from Silverlight toolkit. Lets see how all this fits together to get this to work.

Bridge between Javascript and Silverlight component

In one of earlier posts, How to setup communication between silverlight applications, I discussed how you set this bridge up. The sample project for that article was done using Silverlight 2. The mechanism to set up the communication bridge has not changed in Silverlight 3. So all those concepts still apply for this project as well. The following code snippets shows declaration of a method decorated with ScriptableMember attribute to let silverlight framework know that this methos is to be exposed to javascript. And in constructor of the page, HtmlPage.RegisterScriptableObject method is called to register the class to be exposed to javascript. I do not want to expose all my properties, fields and methods to javascript. So I have not added scriptable attribute on class itself. I want to control what is exposed and what is not.


public MainPage()
{
	InitializeComponent();
	HtmlPage.RegisterScriptableObject("ClockDataClient", this);
	SetupChartDisplay();
}
		
[ScriptableMember]
public void PutNewClockData(string xtx, string data)
{
	AddDataPointToPlot(data);
}

This completes what needed to be done from silverlight application to expose its end points to javascript. Now we are going to see what is done on pages to communicate to silverlight control.

Setting up the page

First thing you need on the page is to include your Silverlight control. On Default.aspx you will find the following declaration of object tag that will host the control.


<object id="clockDisplayPlugin" data="data:application/x-silverlight-2," 
  type="application/x-silverlight-2" width="100%" height="100%">
<param name="source" value="ClientBin/ClockLatency.xap"/>
<param name="onError" value="onSilverlightError" />
<param name="onLoad" value="onLoadClockDisplay" />
<param name="background" value="white" />
<param name="minRuntimeVersion" value="3.0.40624.0" />
<param name="autoUpgrade" value="true" />
<a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=3.0.40624.0" style="text-decoration:none">
  <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="" style="border-style:none"/>
</a>
</object>

All this code was generated by wizard when I added test paste to my project. I added a new param declaration to handle load event. This event is fired when Silverlight control has been loaded. On lets see what all javascript is required to send message to silverlight control.


function onLoadClockDisplay(sender, args) {
 objClockDisplay = sender.getHost();
}

function sendLatencyData(data) {
 if (null != objClockDisplay) {
  objClockDisplay.Content.ClockDataClient.PutNewClockData("", data);
 }
}

As you can see, in load event handler I saved the reference to Silverlight control object. Then from my ajax request code, every time I got the data from server, I call sendLatencyData method. This method calls PutNewClockData method that I exposed from control using ScriptableMember attribute. This call constitutes of four parts.

objClockDisplay.Content.ClockDataClient.PutNewClockData

objClockDisplay is reference to our silverlight plugin. Content is the property on plugin object through which control's methods are exposed. ClockDataClient is the key that was used to register the class as scriptable in our control. PutNewClockData is the name of the method.

Setting up charting control in Silverlight component

I used charting control from Silverlight Toolkit for my project. I decided to use column chart to display latency numbers over time. In silverlight application project, I added the following XAML on MainPage.


<chartingToolkit:Chart Title="Clock Latency" x:Name="latencyChart" BorderThickness="2">
 <chartingToolkit:Chart.Series>
  <chartingToolkit:ColumnSeries Title="Latency" DependentValueBinding="{Binding Latency}" AnimationSequence="Simultaneous" />
 </chartingToolkit:Chart.Series>
</chartingToolkit:Chart>

In codebehind i created a collection to save data sent from javascript and attached the column series to that collection. I only keep last 11 entries in the collection.


void SetupChartDisplay()
{
 ColumnSeries cs = latencyChart.Series[0] as ColumnSeries;
 foreach(var lItem in cs.LegendItems)
 {
  lItem.Visibility = System.Windows.Visibility.Collapsed;
 }

 latencyChart.Width = 500;
 (latencyChart.Series[0] as DataPointSeries).ItemsSource = DynamicCollectionItemsSource;
}

You can see it was pretty simple to set this whole up and get javascript to send data to silverlight control and render the charts using those numbers.

Click to see demo

Feel free to send any comments or suggestions.

Views: 3221

Tags: , ,

HTMLParser | JQuery | Silverlight

Wrong use of timers in Javascript causes Browser CPU Usage to Increase

by Viper 16. July 2009 05:08

I was investigating an issue on a site. Under certain conditions, the web page was becoming unresponsive and CPU usage on machine was mounting to 100% and making the machine unusable. I could not reproduce the problem easily. After asking few more questions to user, I found out that it was happening when the user came to the page after clicking on the link from a certain page. And there was another issue being seen some users. If they leave the page open all night long, by morning time the memory usage in the browser had increased to more than 150MB, CPU usage was close to 50% and machine was very sluggish. After they killed the browser instance, the machine became normal.

After investigating the page's implementation, I saw that there was lot of asynchronous (AJAX) type of implementation. The page was getting multiple pieces of response from server at different interval of times. After looking at the javascript on the page, I saw there were lot of usage of setTimeout and setInterval functions to do things like, clock ticks, requesting data from server etc. I noticed that in one work flow there was following piece of code.


function doTickTock(){
  myTimer = setTimeout("doTickTock()", 1000);
}

This code was calling the method every second. There were couple of issues with this piece of code. I will discuss those little later. I created a small page with few lines of javascript to simulate the code. Here is that piece of code.


<script type="text/javascript">
function clockTick1() {
 document.getElementById("clientClockSpan").innerHTML = new Date().toTimeString();
 clockTimer = setInterval("clockTick1()", 1000);
}

function clockTick2() {
 document.getElementById("clientClockSpan").innerHTML = new Date().toTimeString();
 clockTimer = setTimeout("clockTick2()", 1000);
}


When I used clockTick1() method, my machine's CPU usage mounted to 75% in about 15 seconds and then machine became so sluggish that I had to kill it. But when I used clockTick2() method, i did not see any sluggish behavior. To understand this behavior, you should know the difference between setInterval and setTimeout methods. setInterval calls the function passed in as first parameter after every interval of time that is passed in as second parameter. So it is setting up a timer that will tick at fixed interval. Where as setTimeout only calls the method once after the set interval of time. So when I used clockTick1, every second it was calling the method. But there was one bad thing it was doing. It generated another timer to call the same method every second. So you the number of active timers were increasing exponentially. And they brought the browser to halt. What this piece of code did not do was to call clearInterval to destroy the previous timer before creating new one. So the code should have looked like as below.


function clockTick1() {
 document.getElementById("clientClockSpan").innerHTML = new Date().toTimeString();
 if (clockTimer != null){
   clearInterval(clockTimer);
   clockTimer = null;
 }
 clockTimer = setInterval("clockTick1()", 1000);
}

You will notice that I followed the best practices of setting timer object to null to dispose it off. If you do not do that, the garbage collector will reclaim these unused timers but it will do when its runs next time. But for that period of time, you may observe increased usage of memory by browser along with high usage of object handles. Well usage of handles is important because if they are not reclaimed quickly your browser may start becoming sluggish. So treat these timers very carefully.

Even in the function where setTimeout is being used, make it a practice to clear timer object before setting new one up.

Views: 1295

Tags:

HTMLParser

How to login into ASP.Net application programatically

by Viper 7. April 2009 12:33

Some time back I discussed How to submit requests to web sites programatically using HttpWebRequest. As I discussed in that article that back bone of the whole process is to know the structure of the page along with FORM parameters that need to be passed to target URL. Well that works for most of the application. You run into problem when you are dealing with ASP.Net because of its event model that gets used ASP.Net framework. If you follow the procedure discussed in last article, you will notice that most of the time you are not able to login into the site programatically. There is nothing wrong with the method that I discussed. There is little quirk for ASP.Net and that requires little understanding of how ASP.Net event mechanism works. So I will give brief description, you can read details in microsoft documentations

.

If you look at source of an ASP.Net page, you will notice a hidden input variable __EVENTTARGET. When you click on some control that triggers postback, this variable is used to store ID/Name of that control. And this variable gets passed on to server when FORM is submitted. ASP.Net framework looks at this variable to decide what event handler needs to be triggered.

Given that information, if you do not pass correct value of the control that triggers log in action, sending HttpWebRequest with just login credentials is not going to work at all. Because your request will go to server, and it will never reach the event handlers that handles click on that button. So when you are dealing with ASP.Net sites, check ID/Name of the button or control that user clicks to start login process. You will need to pass that ID/Name as additional FORM key-value pair in POST or GET request. Following code snippet shows that this is about.


reqAttribs.RequestParameters.Add("txtEmail", "xxxxxxxxx");
reqAttribs.RequestParameters.Add("txtPassword", "yyyyyyy");
reqAttribs.RequestParameters.Add("__EVENTTARGET", "btnSubmit");

Notice third request parameter that I added which is ID of input button control. Hope this information helps in understanding programatic login process for ASP.Net sites.

Views: 4983

Tags: ,

.Net | HTMLParser

Error parsing configuration file or file is missing error thrown when using HTMLParser.Net

by Viper 19. February 2009 15:54

When you are using HTMLParser.Net you may run into this error. The reason for this error is that the library depends on presence of following two configuration files.

  1. htmlparser-default.xml
  2. htmlparser-site.xml

This is the error message you will get from exception handler.

The type initializer for 'Winista.Text.HtmlParser.Http.HttpProtocol' threw an exception.

Library expects these two files to be present in the folder from where your application is being executed. If you are using it in ASP.Net application then it will expect it to be in BIN folder of application. In community version of the library it is not possible to specify location of these files. But in PRO version of the library you can set the folder path where these configuration files are present and then library will grab the files from there instead of from execution folder.

Views: 1028

Tags:

HTMLParser

Using firebug to help with web page html parsing using HTMlParser

by Viper 22. January 2009 16:45

For a long time I have been using my application to parse Microsoft Knowledgebase articles and store the content locally to display these articles. All of a sudden the parser stopped working. When I started debugging I realized that there was some changes made by Microsoft on their knowledgebase pages that altered how the flow of mark up. When I initially did the application I had to save the page as HTML and then open it up in Visual Studio editor and format to figure out the structure. Not any more. Now we have handy dandy tool called FireBug that I can fireup and easily figure out the structure of the pages. You can do the same with Internet Explorer Developer Tool bar as well. After that my code to parse the page was reduced down the following snippet.


NodeFilter tableFilter = new NodeClassFilter(typeof(TableColumn));
NodeFilter obAttribFilter = new HasAttributeFilter("class", "listContainer");
NodeFilter andFilter = new AndFilter(tableFilter, obAttribFilter);
NodeList tblNodes = obParser.ExtractAllNodesThatMatch(andFilter);

I use HTMLParser.Net for all my web page parsing. Thats what reduced the parsing to those 4 lines of code.

Views: 935

Tags:

HTMLParser

Powered by BlogEngine.NET 1.5.1.7
Theme by Naveen Kohli