December 2008 Entries

[If you are looking for a quick answer, jump here.]

Yesterday morning was probably one of my least favorite in recent memory.  I arranged to take the day off to go shopping with my wife, but I had to check-in to make sure everything was okay at the office.  I checked my email from home and found that there were suddenly two issues reported on my project that was scheduled for an update in production that night.

Needless to say I had to address the problems.  It turns out that neither were more than a five minute fix in each case.  However, I got slammed with an unrelated issue on my laptop that brought me down to a crawl.  At one moment I was reproducing the error the users reported, the next I made the code change and tried to run the web application again and got a totally unrelated error: " ajax client-side framework failed to load".

I searched the web and found lots of hits, but wasn't having any luck.  Most of them involved deployment to another server.  In my case, AJAX just suddenly stopped working on my box.  I was in dire straits.  I needed to get the fix to the customers as soon as possible, and I had no way to confirm it.

I described the problem to my wife, and I discovered yet another reason I can be certain I married the right woman.  She simply said to me, "Why don't you try it on your other computer?"  Duh!

I had upgraded a few months back from one laptop to another.  So, I still had the old laptop laying around.  I just needed to get the project updated from svn.  After that I was able to make the fix, test and deploy. 

Resolution However, I still needed to figure out what was going on with my new machine.  I left it alone yesterday and picked it back up again this morning.  I gave up on my Google search temporarily and found .Net 3.5 SP1 in my Control Panel - Add/Remove Programs.  I clicked Change... and was relieved to see a "Repair" option.

With bated breath I waited for Windows to complete the repair.  After a few minutes of reading blogs in Google Reader, I saw that the repair was complete.  Now for the test.  I ran my web application and all of the Ajax errors disappeared. 

Perhaps this was coincidental; who knows.  I suppose I could go through my logs, but I'm back in business and that is good enough for me.  Of course, this doesn't explain how Ajax got broken in the first place.

Today I was working on a WebForm that includes a GridView which presents text boxes for various columns.  I put these in the ItemTemplate so all of the rows could be edited at any time.  The next requirement was to update certain read only columns (e.g. Total Amount) based on the changes of the others. 

Originally, I had the entire GridView in an UpdatePanel, but that quickly proved to be a problem for two reasons.  First, the updates were fairly slow.  Second, the active control would lose focus after the partial postback.  I briefly considered what I might do to "restore" the control focus, but decided to consider options other than the single UpdatePanel.

Another fleeting thought was to use an UpdatePanel for each control that could change or be affected by a change.  That's a scary proposition.  For my form, that would result in seven update panels per row!

While reading about the "dangers" of update panels, I came across a couple of posts about PageMethods.  This appeared to be exactly what I needed.  There would be no partial postback as required by the UpdatePanel.  In fact, there would be no postback of any sort.  The PageMethod would simply execute a WebMethod followed by provided success or failed callbacks.

A small amount of javascript and a couple of static methods on my webform later, and I was in business.  The changing of data and tabbing through text boxes was lightning fast.  And there was never any concern over losing control focus because none of the controls were re-rendered.

Here's a snippet of the javascript:

    1 <script type="text/javascript">

    2     function BaseAmount_Changed(ctrl, orderId, totalCtrl, changeCtrl) {

    3         var text = ctrl.value;

    4         var context = {};

    5         context.totalCtrl = $get(totalCtrl);

    6         context.changeCtrl = $get(changeCtrl);

    7         PageMethods.BaseAmount_Changed(orderId, text, OnSucceeded, OnFailed, context);

    8     }


   10     OnSucceeded = function(result, userContext, methodName) {

   11         var results = result.split(":");

   12         if (results[0] == "true") {

   13             userContext.totalCtrl.innerText = results[1];

   14             userContext.changeCtrl.innerText = results[2];

   15         }

   16     }


   18     OnFailed = function(error, userContext, methodName) {

   19         alert('Change Failed: ' + error.get_message());

   20     }

   21 </script>

And the WebMethod declaration:

    1 [WebMethod]

    2 public static string BaseAmount_Changed( int orderId, string text )

Recently, I ran into a problem where I needed to cast from an unknown type to a known type.  Normally this would be fine as I a generic cast.  For example...

    1 public static T ValueOf<T>( this OracleCommand command, string parameterName )

    2 {

    3     return (T)command.Parameters[parameterName].Value;

    4 }

The parameter of course returns an object and I wanted to streamline the parameter value lookup process.  All was well until I started using ODP.Net (instead of Microsofts OracleClient).  With the OracleClient, the underlying type would be a standard system type.  So myCommand.ValueOf<DateTime>("myDateParam") would work fine.  However, ODP would return proprietary oracle types like OracleDate and myCommand.ValueOf<DateTime>("myDateParam") would fail at runtime.

This puzzled me at first (still does really), because there are explicit cast operators between OracleDate and DateTime.  The problem lies in the fact that we are still dealing with Object, not the specific type. 

While debugging I notice something interesting.  Though the system could tell the underlying type was OracleDate it still referenced it as Object.  So (DateTime)myObject would fail at runtime, but (DateTime)(OracleDate)myObject would not.

I was very close to abandoning my ValueOf extension as it didn't really do much anyway.  But I did some searching on other ways to cast dynamically.  I found this post that gave me a kick start.

    1 public static T CastTo<T>( this object input )

    2 {

    3     Type outputType = typeof( T );


    5     if(outputType.IsInstanceOfType( input ))

    6         return (T)input;


    8     Type inputType = input.GetType();

    9     MethodInfo method = inputType

   10                             .GetMethods( BindingFlags.Static | BindingFlags.Public )

   11                             .FirstOrDefault(

   12                                 m =>

   13                                     m.Name.In( "op_Implicit", "op_Explicit" ) &&

   14                                     m.ReturnType == outputType );


   16     if(method == null)

   17         throw new InvalidCastException( string.Format( "Cannot cast from {0} to {1}", inputType.Name, outputType.Name ) );


   19     return (T)method.Invoke( null, new object[] { input } );

   20 }

By the way, line 13 contains "In", an extension method I blogged about a while back.

I am not sure that using reflection will pay off in the end, but I don't expect it to be a problem for now.  None of the places where I am using it involve bulk operatons.  My updated ValueOf looks like this:

    1 public static T ValueOf<T>( this OracleCommand command, string parameterName )

    2 {

    3     return command.Parameters[parameterName].Value.CastTo<T>();

    4 }

Still, I find it strange that the runtime generic cast isn't smart enough to handle this on its own.  Perhaps a proper understanding of the CLR type system would explain a few things.