Exploring the depths and potentials of ASP.NET RSS 2.0 or Subscribe to .BenRush by Email
 Sunday, April 30, 2006

ASP.Net Atlas gives Javascript the concept of a "strong type" in much the same way that .Net strongly types objects: through the use of metadata. Occasionally in the MS core javascript code you may see something that looks like this:

var sourcePropertyType = Sys.TypeDescriptor.getPropertyType(propertyObject, propertyName);

Or, possibly, something like this:

Sys.TypeDescriptor.setProperty(propertyObject, propertyName, value);

This begs the question "what is Sys.TypeDescriptor"? It is very similar to System.Type in the .Net runtime in that an instance of it can encapsulate all relevant information regarding a type (such as its methods, properties, etc.). Under the hood, the .getPropertyType method looks like this:

Sys.TypeDescriptor.getPropertyType = function(instance, propertyName, key) {
   if (instance == null) {
      throw Error.createError('instance is null in TypeDescriptor.getPropertyType');
   }

   if (Sys.ICustomTypeDescriptor.isImplementedBy(instance)) {
      return Object;
   }

   if (key) {
      return Object;
   }

   if ((propertyName == null) || (propertyName.length == 0)) {
      throw Error.createError('propertyName is null');
   }

   var td = Sys.TypeDescriptor.getTypeDescriptor(instance);

   var propertyInfo = td._getProperties()[propertyName];
   debug.assert(propertyInfo, String.format('Property "{0}" not found on object of type "{1}"', propertyName, Object.getTypeName(instance)));

   return propertyInfo.type;
}

The most interesting part in the above method is the call into Sys.TypeDescriptor.getTypeDescriptor, and then the use of the returned type descriptor to _getProperties() and return the .type on the returned property of name 'propertyName'. By following this call chain, you eventually see that, for each object, the method .getDescriptor is being called (so that when you want to get the type information for a particular object, the getTypeDescriptor eventually calls getDescriptor). What gets returned is, an INSTANCE of the following:

Sys.TypeDescriptor = function() {
   var _properties = { };
   var _events = { };
   var _methods = { };
   var _attributes = { };

   this._getAttributes = function() {
      return _attributes;
   }

   this._getEvents = function() {
      return _events;
   }

   this._getMethods = function() {
      return _methods;
   }

   this._getProperties = function() {
      return _properties;
   }
}

This, like, System.Type in the .Net runtime, maintains an internal list of all type information related to an object within the clientside Atlas framework. Objects build this instance when asked for it like this:

this.getDescriptor = function() {
   var td = Sys.Data.DataSource.callBaseMethod(this, 'getDescriptor');

   td.addProperty('data', Object);
   td.addProperty('autoLoad', Boolean);
   td.addProperty('initialData', String);
   td.addProperty('isDirtyAndReady', Boolean, true);
   td.addProperty('isReady', Boolean, true);
   td.addProperty('loadMethod', String);
   td.addProperty('rowCount', Number, true);
   td.addProperty('serviceURL', String);
   td.addProperty('parameters', Object, true);
   td.addProperty('serviceType', Sys.Data.ServiceType);
   td.addMethod('load');
   td.addMethod('save');
   td.addEvent('dataAvailable', true);

   return td;
}

If you see above, the .type of "isReady" is a boolean. Therefore, Sys.TypeDescriptor = System.Type and works in many similar ways.
kick it on DotNetKicks.com
Sunday, April 30, 2006 3:21:39 PM (Central Standard Time, UTC-06:00)  #    Comments [0] - Trackback
Computing
 Saturday, April 29, 2006

Today I got the following compile-time error:

"Unrecognized attribute 'appliesTo'. Note that attribute names are case-sensitive.  "

When trying to compile an application using Microsoft ATLAS. The problem was that, for some reason, Visual Studio was using an old beta2 version of the Microsoft.Web.Atlas.dll module on my machine in lieu of the latest April CTP available here: http://www.microsoft.com/downloads/details.aspx?FamilyId=B01DC501-B3C1-4EC0-93F0-7DAC68D2F787&displaylang=en.

...Once I installed the package above on the machine, everything worked; apparently this machine hasn't been updated with the latest bits in quite some time.


kick it on DotNetKicks.com
Saturday, April 29, 2006 6:38:49 PM (Central Standard Time, UTC-06:00)  #    Comments [0] - Trackback
Computing
 Friday, April 28, 2006

Microsoft built into ATLAS some fairly interesting frameworks (collectively known as the script core) that can be utilized programmatically to make the language feel more .Net-ish for .Net developers. For example, .Net programmers are use to being able to go .trim() on every string object; and we're also use to ICollection symantics (.Add, .Remove, .Contains, etc). The script core added this functionality and gave programming javascript in the Atlas framework a more OO feel. But, the WAY Microsoft accomplished this was of interest to me, and so I cracked open the code for the Script Core (AtlasRuntime.js) and peered inside.

If the following bit of code (which executes perfectly fine under IE7) looks odd to you, then you won't understand how MS did it:

function page_load(){
   Function.prototype.googliebah = "10";
   alert(page_load.googliebah);
}

Look very carefully above, see that I'm calling a method ON a method!?! The point to take from this statement is that everything is an object in javascript, including methods (this isn't a ground-breaking idea, it's been around for quite some time, actually). The next point to take away from this is that I, basically, extended functionality that existed within the javascript language at runtime; namely, gave the 'function' keyword extra functionality. :)

Okay, so we can do more, take this for example:

function page_load(){
   Array.prototype.extraValue = 2;
   var arr = new Array(1);
   arr[0] = 1; 
   alert(arr.extraValue);
}

Note how I extended the capabilities of the "Array" object in javascript (which is a built-in datatype). The same capabilities exist for methods too, meaning you can add methods (which include .Add, .Remove, .Contains, etc.) to datatypes built into the language. Now, what about our own types? Javascript is prototypical, meaning that its type-system is founded atop prototypes, or objects that it types properties and methods from. Given that a function is an object, and you create an object in javascript like this:

function MyObject() {
   this.MyValue = 10;
}

function page_load(){
   var mo = new MyObject();
}

You can very easily add a .Whatever() method to ALL datatypes that are instantiated in the script runtime by simply tagging onto the Function prototype we saw earlier a .Whatever() method. Any object that is created using the 'new' keyword, then, (so long as it sees the javascript code that extends the Function prototype) will have that method. So......say that Microsoft wanted to add a .trim() function to the String datatype in javascript so that us .Net programmers that are used to it can go ahead and use it; well, peer inside AltasRuntime.js and see them adding it (taken from AtlasRuntime.js):

String.prototype.trim = function() {
   return this.trimRight().trimLeft();
}

...and, folks, that's how they're doing it. Happy coding.
kick it on DotNetKicks.com
Friday, April 28, 2006 1:15:57 PM (Central Standard Time, UTC-06:00)  #    Comments [0] - Trackback
Computing
 Thursday, April 27, 2006

The most pramatic way to describe databinding is that properties of one object or resource are linked to those of another object or resource, typically in a "push" fashion; that is, once a property value changes, those other properties that are databound to it auto-magically have their values updated as well. One of the many things that the Atlas framework provides is that of databinding of one control on the web page to another. I got curious....how does it work?

A less pragmatic way of laying out databinding is the following:

"Object A's property value P1 is computed by method m, which uses the state of object B's property P2 when event E occurs".

ASP.Net "Atlas" supports databinding by utilitizing a binding object that is instantiated and assigned to the control whose values are to be bound (the "binder", not the "bindee"); the various properties of the binding object declare what properties are bound, what event they are to be updated by, and what translation of the data is to happen before assignment (transference) occurs. Therefore, the binding object holds onto P1, P2, m (and its parameters), and B from the above statement. When the binding object is handed to the control whose state is to be bound, then A is assigned to the binding object. Clear as mud? Here's an example:

// Create the binding on the textbox
var binding_1 = new Sys.Binding();
binding_1.set_dataContext(checkBoxBoolean);
binding_1.set_dataPath('checked');
binding_1.set_property('text');
binding_1.set_transformerArgument("Checkbox is {0}.");
binding_1.set_direction(Sys.BindingDirection.In);

The code above is taken from one of the quick-start samples provided by Microsoft and it shows the programmatic way (non-declarative way) of creating a binding object (whose type is Sys.Binding()). Note the following while taking into consideration the quoted statement from before:

1) dataContext := Object B
2) dataPath := P2
3) property := P1
4) transformerArgument := m's parameters.

The direction (set_direction()) simply states who gets and who gives in the binding relationship (who is "A" and who is "B").

What's missing, then, is the "translator" or the method "m" from above:

// This is the built-in transform ToString
binding_1.transform.add(Sys.BindingBase.Transformers.ToString);

And then the assigment of the databinding object to object "A": 

// Add the bindings to the controls
textBox.get_bindings().add(binding_1);

By looking at the client source, I know that all that's happened so far is pure assignment of member variables within the newly instantiated binding object; literally no algorithms have ran and nothing has been "hooked up", so-to-speak. Nothing more happens until the sink object (object "A" in our example) has its initialize method called. The source for .initiliaze() looks like this:

this.initialize = function() {
   Sys.UI.TextBox.callBaseMethod(this, 'initialize');

   _text = this.element.value;

   _changeHandler = Function.createDelegate(this, this._onChanged);
   this.element.attachEvent('onchange', _changeHandler);

   _keyPressHandler = Function.createDelegate(this, this._onKeyPress);
   this.element.attachEvent('onkeypress', _keyPressHandler);

}

I intentionally highlighted the callBaseMethod() method, as it calls into the base method for the Sys.UI.Textbox type:

this.initialize = function() {
   if (_bindings) {
   for (var i = 0; i < _bindings.length; i++) {
      _bindings[i].initialize(this);
      }
   }

   _initialized = true;
}

And this is where the magic happens. Note how each member of the binding collection has their initialize() method called, passing in the 'this' pointer (the assignment of object "A" from earlier). Inspecting the .initialize() method of the binding type:

this.initialize = function(target) {
   Sys.Binding.callBaseMethod(this, 'initialize', [ target ]);

   if (this.get_automatic()) {
   if ((_direction != Sys.BindingDirection.In) &&
      Sys.INotifyPropertyChanged.isImplementedBy(target)) {
      _targetNotificationHandler = Function.createDelegate(this, this._onTargetPropertyChanged);
      target.propertyChanged.add(_targetNotificationHandler);
   }

   if (_direction != Sys.BindingDirection.Out) {
      var source = this._getSource();
      if (Sys.INotifyPropertyChanged.isImplementedBy(source)) {
         _sourceNotificationHandler = Function.createDelegate(this, this._onSourcePropertyChanged);
         source.propertyChanged.add(_sourceNotificationHandler);
      }

      this.evaluate(Sys.BindingDirection.In);
   }
  }
}

We see that for each binding, a "delegate" is created which wraps the this._onXXXXXPropertyChanged method (either Source or Target). The delegate is then assigned to the source object's propertyChanged delegate collection. So, when, say, a checkbox is checked (going with our earlier example), we see the following code execute within the checkbox type:

this._onClick = function() {
   this.raisePropertyChanged('checked');
   this.click.invoke(this, Sys.EventArgs.Empty);
}

Note the call to raisePropertyChanged. This method takes as a parameter the event name and calls the appropriate delegates in the propertyChanged Event type.

this.raisePropertyChanged = function(propertyName) {
   this.propertyChanged.invoke(this, new Sys.PropertyChangedEventArgs(propertyName));
}

You can see, then, that the delegate makes sure that the callbacks are executed within the binding object when an event occurs -the whole thing is done in a two-way assignment that is somewhat as confusing as ConnectionPoints in old-school COM. What does the callback do? It takes all the values that were given to it way, way back and actually does the transfer and translation of data to from source to sink by calling the transform method (with the transform parameters). After some pre-processing, the callbacks eventually call into one method named "evaulate". It determines which direction the data is going, and calls either evaulateIn or evaulateOut. These final methods call the transform method (assigned earlier) with all the parameters (also assigned earlier) and hooks up the data values - and the end of the story is when Sys.TypeDescriptor.setProperty(_target, _property, value, _propertyKey); executes:

this.evaluate = function(direction) {
   debug.assert((direction == Sys.BindingDirection.In) || (direction == Sys.BindingDirection.Out));

   if (_bindingExecuting) {
      return;
   }
   _bindingExecuting = true;
   if (direction == Sys.BindingDirection.In) {
      this.evaluateIn();
   }
   else {
      this.evaluateOut();
   }
      _bindingExecuting = false;
   }

   this.evaluateIn = function() {
      var targetPropertyType = Sys.TypeDescriptor.getPropertyType(_target, _property, _propertyKey);
      var value = this._getSourceValue(targetPropertyType);

      var canceled = false;
      if (this.transform.isActive()) {
         var be = new Sys.BindingEventArgs(value, Sys.BindingDirection.In, targetPropertyType, _transformerArgument);

         this.transform.invoke(this, be);
         canceled = be.get_canceled();
         value = be.get_value();
      }

      if (!canceled) {
         Sys.TypeDescriptor.setProperty(_target, _property, value, _propertyKey);
      }
   }

   this.evaluateOut = function() {
      throw Error.createError('evaluateOut is not supported for this binding');
   }

 


 


kick it on DotNetKicks.com
Thursday, April 27, 2006 3:00:02 PM (Central Standard Time, UTC-06:00)  #    Comments [0] - Trackback
Computing

.....http://atlas.asp.net/docs/Client/Browser/jsBrowser.aspx.

 


kick it on DotNetKicks.com
Thursday, April 27, 2006 10:33:48 AM (Central Standard Time, UTC-06:00)  #    Comments [0] - Trackback
Computing
 Tuesday, April 25, 2006

If you need to access session state from a webservice, there are a couple things to remember: First, you must enable the client's "cookie awareness". If you're dealing with a web service proxy (.Net) as your client, then you must give the .CookieContainer property of the proxy a valid object instance:

_webService.CookieContainer = New System.Net.CookieContainer()

Second, by default, web service methods do not have session state enabled (they are not setup to use session), and so you also must specify that a web method accesses (requires) session state explicity via the <WebMethodAttribute>:

<WebMethod(EnableSession:=True)>


kick it on DotNetKicks.com
Tuesday, April 25, 2006 2:11:29 PM (Central Standard Time, UTC-06:00)  #    Comments [0] - Trackback
Computing
 Friday, April 21, 2006

....if you need to actually connect through a console session instead of a RDP session, check this out.


kick it on DotNetKicks.com
Friday, April 21, 2006 10:37:30 AM (Central Standard Time, UTC-06:00)  #    Comments [0] - Trackback
Computing
 Friday, April 14, 2006

....add this to your reader: http://blogs.msdn.com/drnick/default.aspx


kick it on DotNetKicks.com
Friday, April 14, 2006 11:33:12 AM (Central Standard Time, UTC-06:00)  #    Comments [0] - Trackback
Computing

Computers Blogs - Blog Top Sites

Archive
<April 2006>
SunMonTueWedThuFriSat
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456
Blogroll
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2009
Benjamin Rush
Sign In
Statistics
Total Posts: 444
This Year: 0
This Month: 0
This Week: 0
Comments: 128
Themes
Pick a theme:
All Content © 2009, Benjamin Rush
DasBlog theme 'Business' created by Christoph De Baene (delarou)