November 2006 - Posts

I've just hit the 4000 mark in the ajax discussion forums
Thu, Nov 23 2006 8:20

Well, never though i'd see the day where i'd make 4000 posts on a forum. But it did happen in the asp.net MS forums...

by luisabreu | 4 comment(s)
Filed under:
Are extenders broken?
Mon, Nov 20 2006 14:51

Yesterday I saw a post on the AJAX discussion forums which stated that an extender stopped working after a partial postback. Since i'm a curious guy, i decided to take some time and investigate the code. The guy with the problem had a really simple sample that reproduced the problem (which is really cool since I really really really - i think you've got the picture - don't have the time to build samples which reproduce errors ;) ) . i couldn't believe in my eyes, but he was absolutely right: after a partial postback, the extender (which was a TextBoxWaterMarkExtender) didn't render the watermark.

Since the web app only had a page, i started by comparing the entries of the demo app with the ones of the web.config that are defined by the sample app that is available with the extenders. Besides having the registration in the web.config (instead of using the @register directive on the page), everything looked the same. After 5 minutes, i've spotted the difference: the demo app that had the problem disabled event validation. If you user extenders, then don't do this...

This breaks all the extenders that need to inject script during a partial postback (and i do think that they all need to do this). And why does that happen? well, basically because the PageRequestManager class (which is used internally by the ScriptManager control) will only render the controls present on a form if event validation is active (don't believe me? then check its RenderFormCallback with reflector - btw, this method replaces the norma rendering perform by the HtmlForm control).

Extenders will only inject their scripts (the ones you get by calling the GetDescriptor method) on a page during the Render method of the ScriptManager control. If you disable event validation, the Render method of the ScriptManager control won't be called and that's a really bad thing if you use extenders (which is not a problem to me since i'm a firm believer in client behaviors ;) )

I still don't know why it only renders the contents of its controls  when even validation is active, but i can assure you that all the extenders placed inside an UpdatePanel will simply stop working after the first partial postback. now, i do really think that disabling event validation isn't really an exotic scenario, so i'd appreciate if someone could explain why was this decision made....

by luisabreu | 10 comment(s)
Filed under: ,
I'm not getting xml-support on beta 2. why?
Sun, Nov 19 2006 6:08

In beta 2, xml-script is maintained in the value-added bits. So, in order to use it, you need to insert the client side script file needed to support its parsing and processing. If you're using a simple HTML page, just drop the previewscript.js file on that page; if you're using an ASP.NET page, then you can load it through a ScriptReference:

<asp:ScriptManager runat="server" id="manager">
  <Scripts>
     <asp:ScriptReference Assembly="Microsoft.Web.Preview" Name="Microsoft.Web.Resource.ScriptLibrary.PreviewScript.js" />
  </Scripts>
</asp:ScriptManager>

btw, the name of resource can be easily obtained through reflector.

by luisabreu | 4 comment(s)
Filed under: ,
Adding/removing UpdatePanels dynamicaly from a page
Thu, Nov 16 2006 17:13

Today I've found another post on the AJAX discussion forums asking info about the "Cannot unregister UpdatePanel with ID XXX since it was not registered with the ScriptManager.This might occur if the UpdatePanel was removed from the control tree and latter added again".

This happens only in dynamic pages, when you have UpdatePanels added to a certain control and then you move it to another control's collection after the init event(ie, you remove the control from the 1st control's collection and add it to the 2nd one). The solution to this is to perform these operations until the end of the PreInit event. If you're pratical and really don't care why this happens, then it's safe to scroll the page or go to the next post (if you're one of the 3 guys that have subscribed this blog ;))

ok, still here? then let's proceed...to understand why you get that error, you must know the following:

  1. during the Init event, the UpdatePanel control registers itself with the ScriptManager control. You can think of this as putting the UpdatePanel in a list maintained by the ScriptManager control;
  2. during the Unload event, the UpdatePanel unregisters itself with the ScriptManager control. As you've already guessed, this means that the UpdatePanel is removed from the internal list mentioned in 1;
  3. you get the previous error when you try to remove an UpdatePanel which is no longer on the internal list maintained by the ScriptManager control

hum, ok...but why am I getting this error? well, what many still don't know is that when you remove a control from a control's collection, the unload method of the removed control called. Yes, that's right! don't believe me? Ok, use reflector and take a look at the RemoveAt method of the ControlCollection class...so, when you remove the control from a control's collection and add it to another, that UpdatePanel will be removed from the internal list maintained by the ScriptManager before time. following? let's enumerate the steps:

  1. during the Init event, the UpdatePanel registers itself with the ScriptManager control;
  2. when it's removed from a control's collection, the UpdatePanel unregisters itself with the ScriptManager control;
  3. the UpdatePanel is added again to another control's collection
  4. during the OnUnload event of the page, the UpdatePanel tries to unregister with ScriptManager
  5. since it's not in the list, ScriptManager generates an exception

hum...but when I added it to the 2nd control's collection (as in the previous example), shouldn't the Init method be called again, resulting in  a new registration? Well, it depends...you see, internally, each control "knows" its current state. So, if you're removing/adding the UpdatePanel during the Load event, when you add it, you won't get the Init call because you're adding the some control and it has already handled the Init event. On the other hand, if you move the UpdatePanel during the PreInit event you won't get into trouble.

Do keep in mind that this is only valid for removing/adding UpdatePanels maitained in a page. If you're just creating a new UpdatePanel, then you shouldn't get this kind of errors.

by luisabreu | 34 comment(s)
Filed under: ,
Why can't page methods have parameters with the same name but with different casing?
Wed, Nov 15 2006 16:43

Short answer: because the internal WebServiceMethodData class is using a Dictionary<string, WebServiceParameterData> and is using the StringComparer.OrdinalIgnoreCase comparer which, as the name suggests, is responsible for performing a case insensitive comparison (in practise, this means that id equals ID, equals Id, etc).

Special thanks to Garbin for pointing the obvious :)

It's important to note that this will be fixed in the next release: http://forums.asp.net/1466410/ShowThread.aspx#1466410

by luisabreu | with no comments
Filed under: ,
Creating events: the easy way!
Thu, Nov 9 2006 16:52

Garbin has another great tip on his blog. He has just publish an event helper which cuts down the necessary code to create an event.

by luisabreu | with no comments
Filed under: ,
Solving a small bug in the bridges
Thu, Nov 9 2006 11:40

As I've mentioned yesterday, I was having some problems with bridges. the problem was that every method call returned an error saying that a NullException was thrown. Well, after looking at the generated code from the parsing of the asbx file and doing some debugging, it was clear that the problem was happening in the protected method ConvertToType. The method is inherited from BridgeHandler and looks like this:

protected object ConvertToType(object argValue, Type paramType)
{
   string text1 = Assembly.CreateQualifiedName("Microsoft.Web.Extensions", "Microsoft.Web.Script.Serialization.ObjectConverter");
     return Type.GetType(text1).GetMethod("ConvertObjectToTypeInternal", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] { argValue,
                                     paramType,    
                                     new JavaScriptSerializer() });
}

The method reuses the private ObjectConverter class introduced by the Extensions dll to perform the conversion. Initialy, I though that the problem was in the ConvertObjectToTypeInternal: i really thought that since the object I was returning back to the server had some null fields, it was causing the problems. In fact, I really think that the ConvertObjectToType method should be called instead since it performs a quick test of seeing if the current object is already of the desired type. Though the ConvertToType object is not virtual, I could "hide" it by using the new keyword and since the method would be defined in the same class that calls it (recall that the method call is performed from the class which results from the parsing of the asbx file"), then by adding that definition in the code behind file I should be able to intercept the call and redirect it to my method. So, I started by adding the following to the bridge class:

protected new object ConvertToType(object argValue, Type paramType)
{
   string text1 = Assembly.CreateQualifiedName("Microsoft.Web.Extensions", "Microsoft.Web.Script.Serialization.ObjectConverter");
     return Type.GetType(text1).GetMethod("ConvertObjectToType", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] { argValue,
                                     paramType,    
                                     new JavaScriptSerializer() });
}

Well, i was relaly convinced that it would work...but, it didn't! damn...however, now i could debug it and fond out exactly where I was getting the exception. See, the problem is that Type.GetType is returning null! Why is that? Well, I'm not a reflection guru but I think that the problem was that the dll is on the GAC and we need to write its full name. So, changing the previous method to this:

protected new object ConvertToType(object argValue, Type paramType)
{
  string text1 = "Microsoft.Web.Script.Serialization.ObjectConverter, Microsoft.Web.Extensions,
     Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
  return Type.GetType(text1).GetMethod("ConvertObjectToType", BindingFlags.NonPublic |
     BindingFlags.Static).Invoke(null, new object[] { argValue, paramType, new JavaScriptSerializer() });
}

by luisabreu | 4 comment(s)
Filed under: ,
Strongly typed collections
Wed, Nov 8 2006 18:34

A good post by my Garbin on how to achieve something close to this...

by luisabreu | 3 comment(s)
Filed under: ,
Bridges and web parts: not looking good at the moment
Wed, Nov 8 2006 18:29

Today, only time for a couple of quick notes:

  • types are now included into bridges by using the GenerateScriptTypeAttribute to include types in the client side (in the CTP, you'd use the <xmlinclude> element
  • i'm having problems when returning complex object back to the server to make a bridge method call (it looks like a conversion issue, which might be easily solved if the code called another method instead of the one it currently calls)
  • I still can't use web parts and have drag-n-drop with an async postback in a simple demo page which provides authentication and web part management. this one is bad because i really really thought i'd be working by now...

tomorrow, there's more!

by luisabreu | 1 comment(s)
Filed under: ,
xml-script in beta 2
Tue, Nov 7 2006 17:25
well, after writing about it in several posts, I think

that all the issues I've mentioned are solve now. btw, you should know that if you don't define a global xml namespace, the AJAX extensions predefined namespace will be used by default.

by luisabreu | with no comments
Filed under: ,
Localizing scripts
Tue, Nov 7 2006 17:18

Well, what about this one? Beta 2 offers support for automatic loading of localized scripts (I hope i got the word right). So, why is this good? Here's a quick example: suppose you need to show messages to the user in the client side and you also need to support users that speak two different languages. How will you do that? maybe by inserting a global variable from an ASP.NET page which tells you the current locale so that you can show the correct error message? Well, guess what (oki, you've already guessed it by know, right?): you can do this easily. The idea is simple; you define your main library file and then several resource javascript files which contain specific locale values for global variables which you're using from your library. So, let's start by creating the "main" library (a simple js file will do it):

//localizado.js
alert( info );
if( Sys && Sys.Application ){
      Sys.Application.notifyScriptLoaded();
}

Nothing new here... the only thing to remember is that info will be inserted by one of the resource files. When you build resource files you must use a predefined name convention: you should call your files library_filename.culture.js. To illustrate what  I mean, i'll create 2 resource files: one in pt and another one in en:

// localizado.pt-PT.js
var info = "Ola"
if( Sys && Sys.Application ){
    Sys.Application.notifyScriptLoaded();
}

// localizado.en-UK.js
var info = "hello"
if( Sys && Sys.Application ){
     Sys.Application.notifyScriptLoaded();
}

The platform can load the correct file for you: you just need to set the EnableScriptLocalization property to true and add the necessary entries to the ResourceUICultures of the ScriptReference element. Btw, don't forget to configure the ASP.NET page to use the correct culture (in this case, I'm using the Auto option so that the current UI culture depends on the language defined on the browser):

<%@ Page Language="C#" Culture="Auto" UICulture="en-UK" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
  <head runat="server">
     <title>Untitled Page</title>
   </head>
<body>
<form id="form1" runat="server">
<asp:Scriptmanager runat="server" id="manager" EnableScriptLocalization="true">
  <Scripts>
      <asp:ScriptReference Path="localizado.js"
          ScriptMode="release" ResourceUICultures="en-US, pt-PT" />
     <asp:ScriptReference Path="localizado.js" 
           ScriptMode="release" />
  </Scripts>
</asp:Scriptmanager>
</form>
</body>
</html>

And that's all for today.

by luisabreu | 1 comment(s)
Filed under: ,
Loading external scripts
Tue, Nov 7 2006 16:51

During beta 1, we could easily load external scripts by adding a <script> element to the page, by using the ClientScriptManager and even by using the ScriptReference element in order to add references to external Javascript files. Beta 2 introduces some changes when you load a script file through a ScriptElement entry. The docs mention this briefly by saying the following:

"Component developers and page developers creating file-based script libraries that are registered
with the ScriptManager control should include a JavaScript code snippet that indicates that the
library has been downloaded by the client. Although this is not required in all browsers,
Safari requires this to be able to dynamically load scripts."

 

After talking with my good friend Garbin (thanks for pointing me in the right direction) and after running some tests, I'd say that this means is that now we must call the notifyScriptLoaded method exposed by the global Sys.Application object. To test this, let's build a simple page. We'll start by defining a Javascript file (test.js):

alert("howdy! I'm an external file" );
if( Sys && Sys.Application ){
   Sys.Application.notifyScriptloaded();
}

Now, you must have noted the test for Sys and Sys.Application. Well, i've put it there since i'm lazy and I'd like to use my libraries in several web apps (which means that it has to run when i have a global Sys.Application object - which allways happens in an AJAX page - and when i don't). btw, i could have gone further and added a test for the method but, as I said, I'm lazy :)

Now, adding the file is really simple, like the following page shows:

<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
   <head runat="server">
       <title>Untitled Page</title>
     </head>
<body>
  <form id="form1" runat="server">
      <asp:ScriptManager runat="server" ID="manager">
        <Scripts>
               <asp:ScriptReference Path="test.js" />
        </Scripts>
     </asp:ScriptManager>
   </form>
</body>
</html>

Nothing to difficult, but still something that must be registered for future use.

by luisabreu | 17 comment(s)
Filed under: ,
Setting the focus on a control after an async postback
Tue, Nov 7 2006 16:28

I already had a post prepared on how to set the focus on a control after an async postback. Unfortunately, it went directly to "garbadge" since now it's all too easy: we can do that by using the new SetFocusmethod exposed by the ScriptManager class. Here's a demo page that does just that!

 

<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
  void h(object sender, EventArgs e)
  {
       manager.SetFocus(info);
   }
 </script>
<html xmlns="http://www.w3.org/1999/xhtml" >
  <head runat="server">
     <title>Untitled Page</title>
    </head>
<body>
 <form id="form1" runat="server">
    <asP:Scriptmanager runat="server" id="manager" />
    <asp:UpdatePanel runat="server" ID="panel">
       <ContentTemplate>
            <asp:TextBox runat="server" ID="info" />
            <asp:Button runat="server" ID="bt" Text="focus" OnClick="h" />
       </ContentTemplate>
     </asp:UpdatePanel>
 </form>
</body>
</html>

by luisabreu | 8 comment(s)
Filed under: ,
.NET 3.0 final version has been released!
Tue, Nov 7 2006 6:45

I've just read it in JPC's blog (which is in Pt) that it's out!

by luisabreu | with no comments
Filed under:
Ajax extensions: beta 2 is out!
Tue, Nov 7 2006 3:34

Yes, the november release is out and you can get it from this page.

by luisabreu | with no comments
Filed under: ,
Testing your internet speed connection
Mon, Nov 6 2006 15:39

Nothing new, but an interesting site that let's you test your connection speed.

by luisabreu | 1 comment(s)
Filed under:
Dino is starting to get it!
Sat, Nov 4 2006 11:33

I'm glad to see that Dino has changed his mind regarding AJAX extensions beta 1. I'm also glad to see him acknowledge that his first post on it just the result of frustration regarding the changes made to beta 1. Everyone makes mistakes. Not everyone is able to say or even admit that they're wrong. It looks like Dino is one of those rare cases...

by luisabreu | with no comments
Filed under: