Post filed in Microsoft.Net 2.0

Silverlight Circular Motion Animation

In this sample I demonstrate how to take a series of UserControls (Simple ellipses) and rotate each in a counter-clockwise circular motion.

The first step in the process is to define a user control and expose both the TranslateTransform and RotateTransform from the TransformGroup object.  This allows us to rotate and move each user control on a specified tick (DispatcherTimer tick).  The timer is controlled by the main page.xaml.

In this example, I start with a single “ball”, begin rotating it, and every second add an additional ball to the animation.  Instead of having each user control have its own animation, I have chosen to use a single DispatcherTimer that iterates over a generic collection of UserControls, to generate the circular motion

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void Page_Loaded(object sender, RoutedEventArgs e)
{
    _centerX = this.Width/2
    _centerY = this.Height / 2
    _timerAnimation.Interval = TimeSpan.FromMilliseconds(20)
    _timerAnimation.Tick += new EventHandler(_timer_Tick)
 
    _timerInserter.Interval = TimeSpan.FromSeconds(1)
    _timerInserter.Tick += new EventHandler(_timer2_Tick)
 
    PlaceBall("Bo")
 
    _timerAnimation.Start()
    _timerInserter.Start()
}

In this handler I determine the center of my circle, place the first control, and define two DispatcherTimers, one for the animation, and one for inserting additional controls into the main Grid. Since the speed of rotation is consistent for each “ball”, I am able to use a single timer which iterates over a generic collection of UserControls. Each time the Animation timer fires, I will call the following method.

1
2
3
4
5
6
7
8
9
10
11
12
void _timer_Tick(object sender, EventArgs e)
{
    foreach(KeyValuePair<string ,BALL> ball in _balls)
    {
        ball.Value.Rotate.Angle -= 5
        ball.Value.Rotate.Angle %= 360
        // Transform angle degrees to radian value
        double radians = ((ball.Value.Rotate.Angle / 180) * Math.PI)
        ball.Value.Translate.X = _centerX + Math.Cos(radians) * _radius
        ball.Value.Translate.Y = _centerY + Math.Sin(radians) * _radius
    }
}

The math in this method is pretty basic, on each tick I rotate the ball between 1 and 360 degrees. The angle I am looking for is the remainder of the angle of my rotation from 360 degrees. To calculate this, I apply the modulus assignment operator to my new angle. To determine the appropriate X and Y position I transform my angle into Radians and apply a bit of trigonometry to calculate X/Y based on the sin and cosine of the radian. Thanks again to Paul Ortchanian flash site, reflektions for a Flash sample I could translate into Silverlight.

Code: CircularMotion.zip

FBJS and Ajax to acheive Facebook profile link tracking

In interactive application development we love our ability to track and analyze the behavior of our users. Through tools like Google analytics and Urchin, web sites can monitor and analyze where their users are going, and more importantly how those users are getting there.

As our company delves deeper into creating applications for the Facebook platform, we have realized that analysis of users behavior is extremely important. It is no secret that very few companies have mastered how to create a success Facebook application. Those that have seen moderate success do one thing consistently, they all leverage the social graph, but outside of that there is no clear blue print to success. Using techniques such as user tracking we can begin to tune the way a Facebook applications evolves as a way to change its presentation based on the behaviors of its users.

Integrating analytics into a canvas view it is pretty simple, slap in some Google analytics and you can begin to monitor and tune user traffic. The profile view is much more challenging. In the profile view an applications FBML and images are cached and delivered from a Facebook server. Using traditional Google analytics in the profile is not possible. I hope someday Facebook will show us how many users view and interact with a users profile, but until then we need some way to track a users interaction with our application. Back in October Facebook gave developers the ability to do some restricted Javascript and Ajax. With these two features, we can begin to track what links a user click and how those clicks relate to a users interaction with the canvas view. The following snip of FBJS will post a small JSON array to a external location, which in turn will asynchronously store that data for later analysis.

1
2
3
4
5
6
7
8
9
10
11
12
<script><!--
    var uid = '111111';
    function track(a, pid, method) {
        // ajax query
        var ajax = new Ajax();
        ajax.responseType = Ajax.RAW;
        ajax.requireLogin = false;
        var queryParams = { "pid" : pid, "method" : method, "uid": uid, "source": "profile"};
        ajax.post("http://url.com/tracker.ashx", queryParams);
	return true;
    }
//--></script>

To enable this tracking we must add the following callback attached to that elements onclick event. In our example we are attaching tracking to a link which provides an external vendors affiliate link for a series of consumer products.

One caveat, this approach only works correctly in Firefox if your <a> target is set to blank. If you need to use the same window, the only approach I have found is to use the anchor that is passed into the track method combined with the ajax.ondone callback to set the document.setLocation to the anchors href.

1
2
3
4
5
6
ajax.ondone = function() {
var href = a.getHref();
   if (href.length > 1) {
      document.setLocation(a.getHref());
   }
}
1
<a href="http://www.amazon.com" onclick="track(this,12345,'buy');" class="buy" target="_blank">BUY</a>

On the back end we have a page that is waiting for this specific Ajax post, and will return a 1 for success and a 0 for failure. It is extremely important to keep this tracking as efficient as possible. Facebook Ajax has a <10 second maximum timeout on all requests. In our design, the storing of the data is done using a asynchronous thread that queues up the incoming requests in hoped to avoid Facebook having to wait for us to store the data correctly.

Convert a int[] to string[]

This morning I needed to convert an array of integers to strings and I stumbled across this nice little Array.ConvertAll generics method. My example is quite simple, but this technique could be used for much more complicated explicit casting.

1
2
3
4
5
6
7
int[] values = new int[]{1,2,3,4,5}; 
string[] strValues = Array.ConvertAll(values, new Converter(IntToString)); 
.... 
public static string IntToString(int integer) 
{ 
  return integer.ToString(); 
}

SimpleXmlParser

For the recent Facebook platform integration project I was tasked with parsing various forms of Xml returned from the Facebook REST web service. REST or Representational State Transfer, is a term coined by Roy Fielding in his Ph.D. dissertation to describe an architecture style of networked systems. In the Facebook world, to get back some data from there servers you make a POST to a specific PHP page (http://api.facebook.com/restserver.php). The results are returned as an Xml document. In PHP there is a library called SimpleXmlParser which can be used to parses a XML file into a data structure. In the Microsoft.NET world we have the XmlReader class which provides forward-only, read-only access to a stream of XML data. In .Net the XmlReader is the most memory efficient approach to parsing an Xml structure. Unfortunately, those of us who choose to use this class know the level of frustration one will experience when asked to parse an Xml document which contain variable node names.

<?xml version="1.0" encoding="UTF-8"?>
<query>
  <session>2222222222</session>
  <users list="true">
    <user>
      <uid>10000001</uid>
      <name>Person 1</name>
    </user>
    <user>
      <uid>10000002</uid>
      <name>Person 2</name>
    </user>
  </users>
</query>

Examining the Xml arrangement we quickly see a pattern to how we might construct a data structure that would ease our ability to access specific keys within the information. The following is how I would like to parse the Xml data and access the list of users.

SimpleXmlResponse xml = SimpleXmlParser.Parse (fileContents, string.Empty)
SimpleXmlList list = xml["users"] as SimpleXmlList
xml  Count = 2  SimpleXmlResponse
  [0]  {[session, 2222222222]}  KeyValuePair
          Key  "session" string
          Value "2222222222"  object {string}
   [1]  {[users, SimpleXmlList]}  KeyValuePair
          Key  "users" string
          Value Count = 2  object {SimpleXmlList}
                 [0]  {[10000001, SimpleXmlItem]} KeyValuePair
                         Key "10000001" string
                         Value  Count = 2  SimpleXmlItem
                            [0] {[uid, 10000001]} KeyValuePair
                            [1] {[name, Person 1]}  KeyValuePair
                  [1] {[10000002, SimpleXmlItem]} KeyValuePair
                          Key "10000002" string
                          Value Count = 2 SimpleXmlItem
                            [0] {[uid, 10000002]} KeyValuePair
                            [1] {[name, Person 2]}  KeyValuePair

Here are a few things to note:

  • The three objects listed above (SimpleXmlResponse, SimpleXmlList, SimpleXmlItem) are nothing more than classes that inherit from System.Collections.Generic.Dictionary. There purpose is to ease readability and facilitate the casting of the result data.
  • Since SimpleXmlResponse has a value which might contain either a string or a SimpleXmlList, we store this value as an object. This data type will require us to cast the value to string for simple nodes.
  • Each child node contained within those elements flagged as lists (list attribute = true) will have more than one value key pair. As a result, we must either assume the first element is distinct and can be used as the key for the SimpleXmlList element, or we must explicitly identify which element is distinct.

<compilation batch=”false”>

Today some of the C# / ASP.NET 2.0 code I created generated the following error “Circular file references are not allowed”.

After quite a bit of investigation, I realized that this was the result of how I had User Control’s organized within my website. For no good reason I was separating many of my user controls into sub directories within a parent “Controls” directory.

C:\….
+—Controls
+—– Admin
+—– Resources

By default, the compiler will batch assemblies (usually one per folder). This resulted in all files in the “Admin” folders being built into single assembly, while all files in the “Controls” folder where built into another.

In my situation I had a control in the root (Controls) referencing a control in “Admin”, while another control in “Admin” referenced one in “Controls”.

To temporarily get past the compiler issue one can set the batch attribute in the compilation element of the webconfig equal to false. This tells the ASP.NET compiler to not batch assemblies, and instead create an assembly for each user control. Now obviously this is not a good idea in production, but is a great way to get past the error in testing.

The long term solution is to remove the additional sub directories or better organize them.

URL Redirection with Mod-Rewrite ISAPI filter

Recently, one of our clients required that there entire site be optimized for search engines. As part of SEO our goal was to create hackable URL’s and avoid special characters on the query string. This meant no querystring arguments. We choose to use URL rewriting as a way to map dynamic virtual directories to database content.

Our goal was to take a friendly URL like below, and remap them to a more typical aspx page with arguments.

Input:
http://www.client.com/news/press/200703/aquisition
Output:
http://www.client.com/article.aspx?sectionid=22&issue=200703&name=acquisition

For the most part, URL rewriting in ASP.NET 2.0 is pretty straight forward. You create a class that implements System.Web.IHttpModule and register that class as a in the webconfig. All requests made to .aspx pages run through the handler prior to being redirected.

Unfortunately our goal for a friendly URL desired no file or extension, resulting in an interesting issue. Unless we placed a default.aspx page within each physical directory, the request would never fire through the ASP.NET process. Interestingly, ASP does not require this for the root of the site or once you hit 4 directories deep. In both of those situations, asp assumes default.aspx exists, resulting in the HtppModule firing.

Solution:

Our solution was to use a a free ISAPI filter called mod_rewrite (http://www.iismods.com/download.htm). This filter will allow us to append default.aspx to any requests that did not include a file with extension.

This filter is quite easy to use, it is completely configured via an INI file that uses regular expressions combined with back referencing to apply the rewrite. The following is the INI file we use to match requests with both a trailing slash “/” and without.

mod_rewrite.ini

Debug 1
Reload 2000
#Browse LOT
RewriteRule ^([^.]+)/([^/.]+)$ $1/$2/default.aspx
RewriteRule ^([^.]+)/$ $1/default.aspx

We have yet to test this under high load, but expect its performance to be adequate since it excludes everything but the page request.

Loading custom web control from an .aspx Code-Behind page

Yesterday one of our clients requested a simple change to a custom user control for one of their ASP.NET 2.0 site. We made the change, and deployed ONLY the .ascx file to their production server.

The deployment resulted in the following run-time error:

Unable to cast object of type ‘ASP.controls_customControl_ascx’ to type ‘controls_customControl’.

This error appeared to disappear by editing the webconfig file.

The structure of the control we edited was such that it dynamically loaded a second control in its code behind. This was done by making a reference to the custom control through the use of the @Register directive in the .ascx page.

<%@ Register src=”customControl.ascx” mce_src=”customControl.ascx” TagName=”CustomControl” TagPrefix=”uc1″ %>

In the code behind, the control was then loaded and explicitly cast to the appropriate type upon the click of a button in the control.

controls_customControl custom = (controls_customControl)LoadControl(”../controls/customControl.ascx”);
(NOTE: The dynamically loaded control inherits from a class defined in a precompiled assembly)

So what happen?

We all know that when the first request arrives for any page within a folder ASP.NET dynamically parses and compiles all the ASPX pages in that folder. We also know that it compiles any code-behind files associated with ASCX files into a separate assembly. If two pages exist in the same folder they will be compiled into the same assembly. Based on this understanding, I would have predicted that the file being changed would have been enough to trigger a recompile of the control folders assembly, eliminating the error.

Could the behavior come as a result of the @Register directive?

When you load a control programmatically the strong type for the control is available only after you have created a reference to it. By definition @Register is used for declarative inclusion of control in a page. The assembly referenced in the directive is dynamically created the first time the ASP.NET runtime accesses the resource. The instance of the control will be created “on-the-fly” when the page is loaded.

It has always been my understanding that when a programmer chooses to load a control in the code-behind, the strong type of the control is only available after the page has made reference to it, making @Register inappropriate. Without the implicit inclusion of the control in the page, the compiler should throw and error. I believe in our situation it worked because both controls exist in the same directory resulting in them being compiled into the same assembly.

Most documentation suggests that one should use the @Reference directive and NOT @Register when loading controls programmatically. @Reference tells .NET that the referenced control MUST be dynamically compiled and linked. If two controls in the same directory have dependencies on each other through an @Reference directive, they will end up in separate assemblies.

Would this have eliminated my error…time to do some testing!

….to be continued….