July 2008 - Posts

Events in ASP.NET AJAX are quite unlike the events in the .NET framework.  Rather than having explicit events and event handlers, the framework provides a workaround to this approach that doesn't require any custom syntax definitions to JavaScript itself, while still being able to expose the capability.

The approach is to expose events using an events property.  This events property is defined in the Sys.Component class, the base class of all controls and extenders.  The get_events() property setter returns an object of type EventHandlerList.  This object can add event references to client events stored in a key.  For instance, the following methods add, remove, and raise an event.  These methods are located in the prototype definition, which is why the function declaration is at the end.

add_propertyChanged : function(handler) {
    this.get_events().addHandler("propertyChanged", handler);
}

remove_propertyChanged : function(handler) {
    this.get_events().removeHandler("propertyChanged", handler);
}

raise_propertyChanged : function()
{
    var handler = this.get_events().getHandler("propertyChanged");
    if (handler != null)
        handler(this, Sys.EventArgs.Empty);
}

Working with events are done by methods that map the name of the event to a handler.  The event is referenced by a string that uniquely identifies the event.  Any clients registering to this event would register the name of a JavaScript method.  This JavaScript method would be the event handler for the event in the ASPX page that the control or extender resides in.

It's up to something in the AJAX control or extender to call raise_propertyChanged.  When some member does (property or method), this then triggers the propertyChanged event.  An event handler in the ASPX would receive notification of it, and would be passed the sender and event argument (though the method doesn't have to accept these parameters).  An event handler can be wired up like so:

<script language="JavaScript">
    function propertyChangedHandler(sender, e)
    {
         alert("prop changed");
     }

     var ctl = $find('<%= MyControl.ClientID %>');
     ctl.add_propertyChanged(propertyChangedHandler);
</script>

Anything that triggers this event will call the propertyChangedHandler JavaScript method.  This method is a client-side event handler for our purpose.  Something in the component actually needs to call raise_propertyChanged() to fire the event, but our event handler will catch it.

In ASP.NET AJAX components, the typical way to expose events is through a property (as oxy moronic as that may be).  The property stores the name of the JavaScript event handler (propertyChangedHandler) and passes it to the client script when the component is described.  In an ASP.NET AJAX component, this is done using GetScriptDescriptors, with a statement as shown below:

descriptor.AddEvent("propertyChanged", this.OnClientPropertyChanged);

It's by convention to include "OnClient" for event handlers to a client event.  Using the AJAX Control Toolkit approach, events can be declared using the following approach:

[
ExtenderControlEvent,
ClientPropertyName("propertyChanged")
]
public string OnClientPropertyChanged
{
    get { .. }
    set { .. }
}

At runtime, the AJAX component is dynamically described by using the metadata defined in the attributes of the property definition, which it sees that the OnClientPropertyChanged property contains the name of a method that is an event handler.  This event handler is passed to the add_propertyChanged method.  When that event is raised, the event handler defined here gets fired.

Posted by bmains | 3 comment(s)
Filed under:

In JavaScript, there really isn't such as thing as properties.  Essentially a read/write property is represented by two methods, one with a "get_" prefix and one with a "set_" prefix.  However, the ASP.NET AJAX framework separates this as just a method; for instance, the following property definition is shown below:

//note the function declaration after is the prototype syntax, as properties are note
get_text : function()
{
  return this._text;
}

set_text : function(value)
{
  if (this._text != value)
  {
    this._text = value;
    this.raisePropertyChanged("text");
  }
}

In javascript, you can't reference the property via "text" and work with it like a property in .NET.  You have to use the get_text() and set_text("text") method calls; however, in .NET, you can work with it like a "text" property when you describe it.  Every ASP.NET AJAX server control needs to describe its client counterpart in the GetScriptDescriptors method; to describe a property can simply be done by:

descriptor.AddProperty("text", this.Text);

Notice the property doesn't need to specify "get_" or "set_" at all; it can simply reference it as "text" (the framework appends a "get_" or "set_" when it makes the actual assignment.  Also, the second parameter of AddProperty pushes down the current value of Text stored on the server-side, which acts as the initial value at load time.

If you use the AJAX Control Toolkit approach to developing custom controls or extenders you don't need to define GetScriptDescriptors; rather, the framework does it for you using reflection of attributes, shown below:

[
ExtenderControlProperty,
ClientScriptResource("text")
]
public string Text { .. }

ExtenderControlProperty notes that Text should be described as a property, while ClientScriptResources states what the property is named.  You don't need to use ClientScriptResource if the server-side property name matches the client side name, but the matching is case sensitive and our script uses lower camel case instead of upper as on the server, which is why I defiend the attribute.  At runtime, the previous descriptor.AddProperty statement is created automatically for us and the script is described correctly.

Posted by bmains | with no comments
Filed under:

If you've done custom development using the AJAX Control Toolkit, you know that the approach the framework takes is an attribute-based approach.  If you haven't looked at this before, check out this brief example (there are some other sections on the site that are helpful): http://www.asp.net/AJAX/AjaxControlToolkit/Samples/Walkthrough/CreatingNewExtender.aspx.  There are som explanations of the attributes that can be used here:  http://www.asp.net/AJAX/AjaxControlToolkit/Samples/Walkthrough/ExtenderClasses.aspx.

The ComponentReference is a very useful attribute, which I didn't see in the links above.  This attribute can be used on a property that holds the ID of a control.  It will internally find the control reference and provide a reference to the AJAX class for that control.  Let's assume the following property as an example:

public string AjaxControlID { .. }

The AjaxControlID property stores the ID of a control that emits an AJAX script.  An AJAX control has both a server-side component and a client-side component.  For instance, the TabContainer control has an AjaxControlToolkit.TabContainer server component and an AjaxControlToolkit.TabContainer client component.  ComponentReference is a shortcut way, by using the ID, to gain reference to the client component (thie client component has a get_id getter that has the same ID as the control.

While ComponentReference gets a reference to the client component, ElementReference gets a reference to the HTML element that the client component extends.  Every AJAX control and extender works with some underlying HTML element; an extender targets a different HTML element with its javascript, while a control renders its own interface, which means it extends the HTML element it renders.

So if we have a server property:

[
ExtenderControlProperty,
ClientScriptResource("extenderControl"),
ComponentProperty
]
public string ExtenderControlID
{
    get { .. }
    set { .. }
}

Which maps to the client class's property getter/setter defined in the prototype definition:

get_extenderControl : function()
{
   return this._extenderControl;
}

set_extenderControl : function(value)
{
   this._extenderControl = value;
}

The reference to the component for the extender is accessible on the client side; _extenderControl references the custom AJAX class for the extender.  If the property used ElementReference, it would reference the HTML element that the extender represents.

Posted by bmains | with no comments
Filed under:

 If you have developed applications with LINQ to SQL, you know that one of the features of these objects are that they are aware of the DataContext they were created in.  This can have issues in ASP.NET if you do not cache the DataContext it belonged to, because each LINQ to SQL business object knows which context it was created in, and if it isn't the current one, then an exception is thrown.

It's possible to create new business objects without them being known by the DataContext; when you first create an object, until that object is passed along to the DataContext through InsertOnSubmit, the data object can be a temporary holder of data disconnected from the database.  It's also possible to create relationships for the data that are also disconnected from the database, so you can build a whole tree of relationships of objects rather easily, all in disconnected form.

If you like to use that approach, use caution.  If you add one object as a reference to a disconnected object that is DataContext-aware, then all of the other disconnected objects related to that object will all be queued up for insertion, which is a HUGE pain.  If you get a lot of duplicated data, this is the first place to look; is a DataContext-aware object reference being assigned anywhere?  If so, remove it, and make a reference by key.

That can pose problems because one of the nice features of LINQ to SQL is being able to drill-down an object model using the PK/FK properties, but in disconnected mode, all of the data has to be disconnected, and reference data won't work because you aren't usually creating it on the fly.  Creating temporary matching records isn't typically a good idea as well, because if they aren't removed, data will be duplicated, plus removing the objects later may damage the reference for the real value potentially.

So what are the options here?  I'd recommend storing as little disconnected data as posslble, or make sure you tread lightly.

Posted by bmains | with no comments
Filed under:

 So what is the purpose of the descriptor?  The descriptor describes information about the component, such as properties, events, and methods.  For properties, the descriptor states the name and type of the property, as well as whether the property is read-only or if null values are allowed.

So what does that govern?  I was changing a component and found out that it governs a lot because whenever I changed the definition of the property, an exception was thrown at runtime, stating that a readonly property had a setter definition.  So the ASP.NET AJAX framework is aware about your structures through the descriptor, and does perform validation.

Posted by bmains | with no comments
Filed under:

I defined this event:

 

 

 

[

ExtenderControlEvent, ClientPropertyName("mouseOver")]
public string OnClientMouseOver
{
 
get { return (string)(ViewState["OnClientMouseOver"] ?? string.Empty); }
 
set { ViewState["OnClientMouseOver"] = value; }
}

in my AJAX component that uses the AJAX Control Toolkit way of developing controls and extenders.  AJAX Control toolkit uses attributes to describe the client component.  The above property is describing an event handler for the mouseOver event of the underlying HTML element; however, what is happening is that this definition was throwing me an error.

Turns out it is because I use the bolded text above in my null coalesce (??) definition; string.Empty doesn't work well in this case.  I switched to null, and it works fine.

Posted by bmains | with no comments
Filed under:

To a point, LINQ to SQL works well with unit testing.  When the LINQ-to-SQL objects are in a detached state (either not submitted to the database, or detached through the detach command) and there isn't a chance of accidentally updating records or creating new records to the database, LINQ to SQL works really well with unit testing.  Take a look at this example:

Customer customer = new Customer();
customer.Orders.Add(new Order { OrderKey = 1, TotalAmount = 20, OrderDate = DateTime.Now });
customer.Orders.Add(new Order { OrderKey = 2, TotalAmount = 19.50, OrderDate = DateTime.Now });

customer.Reviews.Add(new Review { ReviewKey = 1, ReviewText = "OK" })
customer.Reviews.Add(new Review { ReviewKey = 2, ReviewText = "Liked it" });

At this point, no object has been submitted to the database, or is attached to the data context, so this unit test is isolated.  Although it can be a pain to setup all of the objects needed for a test, it can be done.  You can start processing the test as follows:

CustomerBAL.ProcessOrders(customer);

foreach (Order order in customer.Orders)
    Assert.AreEqual(true, order.IsSubmitted);

And so on.  As long as the components interacting with the objects don't submit the data to the database, or do anything outlandish with the objects, this approach will work well in unit testing.

Posted by bmains | with no comments
Filed under: ,

 Apparently the same workspace name for two different TFS servers is an issue.  I downloaded a new project from the codeplex site, and gave it the same workspace name as a different TFS project.  When I opened the project that has had no problems for years, I started getting "all files must be in the specified workspace.  Workspace <name> contains <folder>." which was real strange.  Of course it was there, I just created it at the time; I got this when I added a new file to the project.

Quickly changing the workspace name to be unique solved the problem.

Posted by bmains | with no comments
Filed under:

 In the second article, I wanted to talk about client object-models.  In JavaScript currently, we do have the ability to do class development.  However, the Microsoft framework provides extensions to this approach (that fit within the JavaScript development approach) to differentiate namespaces, enumerations, interfaces, events, properties, and some of the other constructs.

All of these existing contructs allow for the server to pass values to the client, along with exposing an object model similar to .NET on the client side.  This means that AJAX server controls can have a client model that other controls or JavaScript code in ASP.NET pages can interact with.

Let's look at the client/server communcation capabilities as well.  Because the client code can call a web service, its also possible to have the client code stream data and rerender its interface using that data, all without posting back.  These capabilities already exist through the Sys.Services.AuthenticationService and Sys.Services.ProfileService.  It's possible to login and log out a user, as well as extract their profile information, all on the client side.

The possibilities are endless, especially when Silverlight is thrown into the mix.  More client development means a richer user experience, and to do this in a managed way means less coding effort to do so.

Posted by bmains | with no comments
Filed under:

If you are wondering why you may want to consider using the AJAX client library (forgetting about the AJAX extensions library server portion), there are multiple reasons to choose Microsoft's implementation.

Right now, on the internet, we are seeing a lot of different approaches to developing JavaScript.  There are quite a bit of JavaScript libraries available on the internet outside of Microsoft's implementation (like JQuery or Yahoo YUI).  Each of these implementations are designed to make JavaScript development easier and sometimes more managed.  Microsoft's is the same; however, they have taken a neat approach to custom JavaScript development.

When looking at developing custom controls or extenders in ASP.NET AJAX, the client library helps create a client-side API for the control or extender that ASP.NET pages can make use of.  Picture creating a control that can respond to events, can have property definitions to alter underlying data, or define methods that can be called.  This all can happen on the client side without requiring a postback.  In addition, its really easy to provide custom event handlers to events raised by client components, so the page can respond to an action of an AJAX component on the client side.

Furthermore, this can be taken a step further by having the client-side component re-render the interface whenever the data changes, especially when the data is streamed from a web service called through a proxy.

This is one of the underlying goals with ASP.NET AJAX, and I plan to talk about this in more detail on my blog.  Stay tuned.

Posted by bmains | 1 comment(s)
Filed under:

I just wanted to post a note that I was up for re-evaulation for the MVP award (as it is a yearly thing), and I was renewed for the July 2008-2009 time period.  I am really excited to be renominated, as I think it's a prestigious award, and I'm thankful that I'm in it again for another year.  I look forward to another year of working with Microsoft technology and blogging about it here.

Posted by bmains | 4 comment(s)
The leading UI suite for ASP.NET - Telerik radControls
Outstanding performance. Full ASP.NET AJAX support. Nearly codeless development.