daron yöndem | Microsoft Regional Director | Silverlight MVP
Microsoft Regional Director | Nokia Developer Champion | Azure MVP

After a heavy loaded year with lots of AJAX and Silverlight projects, please welcome my second AJAX Book :) ASP.NET 3.5 AJAX.

The book covers a wide range of topics including JavaScript frameworks like MooTools, jQuery, Prototype, server-side frameworks like AJAX.NET, Anthem.NET and of course all the client-side and server-side features of ASP.NET 3.5 AJAX!

A total of 700 pages will provide you the path from start-up AJAX development to the high-end performance tricks. AJAX enabled WCF apps, LINQ2JSON are just some of the fresh topics in the book.

I would like to thank to Goksin Bakir from Microsoft MEA for his valuable review.

Writing an English book is one of my dreams :) however for the moment ASP.NET 3.5 AJAX is in Turkish.

With the launch of Visual Studio 2008 RTM version we are all experiencing the Multi-Targeting feature of the new IDE. The little problem on the ASP.NET development side is that AJAX Extensions are integrated to ASP.NET 3.5 and we don’t have such a choice for ASP.NET 2.0 which we already had in Visual Studio 2005 with AJAX Extension 1.0. Actually there is no problem developing further an ASP.NET 2.0 AJAX Extension 1.0 application on Visual Studio 2008 which is build with Visual Studio 2005 but what if you want to create new ASP.NET 2.0 AJAX Enabled Web Sites?

Here goes the solution: Microsoft ASP.NET 2.0 AJAX Templates for Visual Studio 2008

http://www.microsoft.com/downloads/details.aspx?FamilyID=5c7df430-1c34-40d2-b6ec-81353b5fcf2e&displaylang=en

Download the package from the address above and after having it installed on your PC you will get your “File / New Web Site” menu targeted to .NET Framework 2.0 having a new choice named “AJAX 1.0 Enabled ASP.NET 2.0 Web Site”.

AJAX 1.0 Enabled ASP.NET 2.0 Web Site Project Template in Visual Studio 2008
AJAX 1.0 Enabled ASP.NET 2.0 Web Site Project Template in Visual Studio 2008

Hope it helps.

Today I represented a webcast hosted by Microsoft Turkey about “Silverlight and ASP.NET AJAX Applications Development”. I did not announce it on my English blog because the webcast was in Turkish. However I guess the source code of the webcast demo can be really useful to people struggling with Silverlight and asynchronous data interaction. Below you can download the Silverlight 1.0 demo application hosted inside an ASP.NET AJAX Web site and the appropriate MSSQL 2005 database creation script files used in the demo.

WebCast Demo Source Code - 07112007_1.zip (118.48 KB)

Good luck ;)

With lots of (I mean LOTS OF :)) bug fixes the new version of AJAX Control Toolkit is released. I strongly suggest to upgrade your current projects and production environment to the new version asap. You can download the control package following the link below;

http://www.codeplex.com/AtlasControlToolkit/Release/ProjectReleases.aspx?ReleaseId=4941

Crystal Tech, one of my favorite hosting providers, announced the new ASP.NET 3.5 Beta Hosting Plan. You can easily get hands on experience on a real-life hosting with full LINQ and AJAX support. The downside is that the servers are running on Server 2003 for the moment. Hope they upgrade to Server 2008 as soon as possible.

Long time I didn’t have the chance to blog, however I have an excuse :) My first book has been published in Turkey -The book is in Turkish as well- with a title of “ASP.NET AJAX”. A total of 516 pages full of ASP.NET and AJAX experiences, including the brand-new AJAX Extension features, both client and server side programming. I’m very happy to be a newbie writer and hope I will go further on soon with new ideas.

Fortify Software’s Security Research Group has introduced a new vulnerability in AJAX based applications: JavaScript Hijacking on their web-site http://www.fortifysoftware.com/advisory.jsp. My first reaction was; “How can it be new?”. AJAX is a new word, or abbreviation, however the technology behind is JavaScript, XML, JSON. Do you get anything new? Of course there is a chance that this vulnerability can be a recent discovery, but it’s not! The only difference is the level of the threat.

Until AJAX has become a popular programming model for Web 2.0, JavaScript was not used to send and receive data from server-side. Today JavaScript is more important and the risks and vulnerabilities are more dangerous. Nevertheless, again.. This is not a recent discovery!

I suggest everyone read the report of Fortify Software’s Security Research Group if you are using your own AJAX framework. For the ASP.NET AJAX Framework developers, Scott Guthrie from Microsoft has posted a nice summary on his blog at http://weblogs.asp.net/scottgu/default.aspx.

Finally, in a nutshell if you are using web services in order to transfer data to the client-side, you need to authenticate users accessing your web services as well as you do for your web page.

Let’s answer the most popular question about UpdatePanels; "How can I update an UpdatePanel with JavaScript on client-side?" Officially there is no tool or library/interface providing this feature. However there is always a solution :) Before going under the hood, I will introduce you my simple solution; UpdatePanelJavaScriptExtender. You can download it and use JavaScript to update your UpdatePanel. Moreover you can send parameters to the code-behind too.

How to use the UpdatePanelJavaScript Extender?

Download the control (link at the end of the article) and add it to your toolbox. Visual Studio will automatically add AjaxControlToolkit reference to your web site as well. The UpdatePanelJavaScript Extender is build on AjaxControlToolkit Extender base libraries.
Secondly, just drag-n-drop the control to your web site.

<cc1:UpdatePanelJavaScriptExtender ID="UpdatePanelJavaScriptExtender1" runat="server" ClientCommand="UpdateMe" TargetControlID="UpdatePanel1" OnUpdate="UpdatePanelJavaScriptExtender1_Update"></cc1:UpdatePanelJavaScriptExtender>

The extender control has three properties. One of them is the well-know ajax extender property TargetControlID. The ID of the UpdatePanel, which will be refreshed with JavaScript, should be assigned to TargetControlID. The second property is ClientCommand. This is the name of the JavaScript command, which you will use to update the UpdatePanel assigned to TargetControlID. The final property is OnUpdate. OnUpdate property should have the name of the code-behind function to run when a client-side update request happens.

Client-side JavaScript command example;

UpdateMe(prompt('Write anything to pass to the UpdatePanel with JavaScript?', ''));

The function name is provided by the ClientCommand property of UpdatePanelJavaScript Extender. The javascript function can have only one parameter, however you can pass as many parameter as you want and any type of object by serializing them with JSON. Of course you will need to de-serialize it on the server-side.

Protected Sub UpdatePanelJavaScriptExtender1_Update(ByVal Sender As Object, ByVal E As System.EventArgs, ByVal parameter As String)    
    Label1.Text = parameter
 
End Sub

The server-side event handler has an extra parameter named as “parameter”. This is the parameter send by the JavaScript function. In our tutorial we are just asking the user to enter any string and passing it to the server side. On the server-side the parameter is transferred to Label1.Text property. Here, in the event handler you can do anything you want. The UpdatePanel will be refreshed after the onload event handler is completed.

The idea behind

When we put a TextBox control inside an UpdatePanel and set its AutoPostBack property to True, the textbox controls onchanged HTML event is filled by a special code causing an asynchronous postback. In order to simulate a client side UpdatePanel.Update function we will insert an invisible TextBox control inside our UpdatePanel and call the javascript function hidden inside onchanged event. The content of the above mentioned TextBox will be our parameter to send to server-side.

Hands-on-Lab

Welcome to the laboratory :) Now we will start building our UpdatePanelJavaScript Extender control. When you start a new ASP.NET AJAX Control Project you will have to edit two files. One of them is a JavaScript file which will work on the client side. The other one is the server side file, which I like the most as a Visual Basic developer :)

First of all, we will add some code to the JavaScript file. The default JavaScript file is already full of code. In order to let you understand what we need to add, I will put extra comment lines.

Type.registerNamespace('UpdatePanelJavaScript');

UpdatePanelJavaScript.UpdatePanelJavaScriptBehavior = function(element) {
    UpdatePanelJavaScript.UpdatePanelJavaScriptBehavior.initializeBase(this, [element]);
    <!--Our CliendCommand Property variable-->
    this._ClientCommandValue = null;
}

UpdatePanelJavaScript.UpdatePanelJavaScriptBehavior.prototype = {
    initialize : function() {
        UpdatePanelJavaScript.UpdatePanelJavaScriptBehavior.callBaseMethod(this, 'initialize');
    },
    dispose : function() {
        UpdatePanelJavaScript.UpdatePanelJavaScriptBehavior.callBaseMethod(this, 'dispose');
    },
    <!--Our CliendCommand Property Code starts here-->
     get_ClientCommand : function() {
        return this._ClientCommandValue;
    },
    set_ClientCommand : function(value) {
        this._ClientCommandValue = value;
    }
    <!--Our CliendCommand Property Code ends here-->
}

UpdatePanelJavaScript.UpdatePanelJavaScriptBehavior.registerClass('UpdatePanelJavaScript.UpdatePanelJavaScriptBehavior', AjaxControlToolkit.BehaviorBase);
<!-- Our TextBox onchange event fires up here -->
UpdatePanelJavaScript.Update = function(HiddenBoxID, parameter) {
      var HiddenBox =$get(HiddenBoxID);
      if (typeof(parameter)=="undefined")
      {
            parameter = "RANDOMPARAM" + Math.random();
      };
      if (HiddenBox.value == parameter)
      {
            parameter = parameter + "RANDOMPARAM" + Math.random();
      };
      HiddenBox.value = parameter;
      var MyCommand = String(HiddenBox.onchange).replace('function anonymous()\n{\n','');
      MyCommand = MyCommand.replace('\n}','');
      MyCommand = MyCommand.replace('function onchange(event) {\njavascript:\n','');
      eval(MyCommand); };
<!-- Our TextBox onchange event cathcer ends up here -->

First, we need to add a private variable for ClientCommand and define set and get methods for it. This was the simple job. The hard one is to write the Update method attached to the UpdatePanelJavaScript namespace at the end of our code. The Update method gets two parameters. One of them is the ID of our hidden TextBox and the other one is the parameter to transfer to server-side. The code finds the hidden TextBox and transfers our parameter inside the TextBox. If the parameter is undefined we assign a random parameter with the prefix of "RANDOMPARAM". This is needed because if the content of the textbox doesn’t change we can’t do a postpack. In addition if the incoming parameter is equal to the content of the textbox we need to add a suffix to our parameter in order to get the textboxs content changed. Further on the onchange event of the TextBox is transferred to a string variable and unwanted codes are cleared. Finally, to start the postback we can launch the code with eval JavaScript function. This Update JavaScript function will be used by other JavaScript functions created by our server-side extender code.

Now is the time for our server-side code. The code-behind file of our extender controls comes with lots of codes as well. First, we will set our base TargetControlID type to UpdatePanel.

<TargetControlType(GetType(UpdatePanel))>

We will define a TextBox control to add to the target UpdatePanel. We need to define it with WithEvents keyword in order to handle its TextChanged event.

WithEvents MyTextBox As New System.Web.UI.WebControls.TextBox

Our extender control will have an Update event. The update event should be defined public. In addition our event will have a third parameter to transfer the incoming parameter from JavaScript, or the text property of our hidden TextBox.

Public Event Update(ByVal Sender As Object, ByVal E As EventArgs, ByVal parameter As String)

We need to define our ClientCommand property on the server-side as well.

        <ExtenderControlProperty()> _
        <DefaultValue("Update")> _
        Public Property ClientCommand() As String
            Get
                Return GetPropertyValue("ClientCommand", "")
            End Get
            Set(ByVal value As String)
                SetPropertyValue("ClientCommand", value)
            End Set
        End Property

Now, we will write the server-side code to set the properties of our hidden TextBox and add it to the UpdatePanel. The visibility and display CSS properties should be hidden and none. On the second step we will create a label control and put our JavaScript code inside it. This is the only way I was able to create control specific code for each extender instance on the same page. The JavaScript file created inside our project will be used globally by all extenders on the web page, nevertheless we need separated codes for each extender to let the user update different panels attached to different extenders. We are creating a JavaScript function pointing to our global Update function inside our JavaScript file by getting the function name from ClientCommand property and transferring the ID of our extenders hidden TextBox. This is one of the tricky parts of this extender control.

        Private Sub UpdatePanelJavaScriptExtender_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
            MyTextBox.AutoPostBack = True
            MyTextBox.Style.Add("visibility", "hidden")
            MyTextBox.Style.Add("display", "none")
            Dim TargetPanel As System.Web.UI.UpdatePanel = Me.TargetControl
            TargetPanel.ContentTemplateContainer.Controls.Add(MyTextBox)
            Dim script As New System.Web.UI.WebControls.Label
            Dim builder As New System.Text.StringBuilder
            builder.AppendLine("<script language='javascript' type='text/javascript'>")
            builder.Append("function ")
            builder.Append(Me.ClientCommand)
            builder.AppendLine("(parameter) {")
            builder.Append("UpdatePanelJavaScript.Update('")
            builder.Append(MyTextBox.ClientID)
            builder.AppendLine("', parameter);")
            builder.AppendLine("};")
            builder.AppendLine("</script>")
            script.Text = builder.ToString
            Me.Controls.Add(script)
        End Sub

Finally, we will handle our hidden TextBoxs TextChanged event in order to get its Text and transfer as a parameter. We will raise our own event with extra parameter. If the incoming parameter is a random one generated by our JavaScript code, we will delete it. If the incoming parameter contains a random parameter in order to allow sending same parameter to cause postpack, we will just remove the random parameter and send the rest to the user.

        Sub Control_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyTextBox.TextChanged
            Dim SenderControl As System.Web.UI.WebControls.TextBox = sender
            If SenderControl.Text.IndexOf("RANDOMPARAM") <> -1 Then
                If SenderControl.Text.IndexOf("RANDOMPARAM") = 0 Then
                    RaiseEvent Update(Me, e, "")
                Else
                    RaiseEvent Update(Me, e, SenderControl.Text.Substring(0, SenderControl.Text.IndexOf("RANDOMPARAM")))
                End If
            Else
                RaiseEvent Update(Me, e, SenderControl.Text)
            End If
        End Sub

Here is the final code of our code-behind file.

Imports System
Imports System.ComponentModel
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports AjaxControlToolkit
 
#Region "Assembly Resource Attribute"
<Assembly: System.Web.UI.WebResource("UpdatePanelJavaScript.UpdatePanelJavaScriptBehavior.js", "text/javascript")>
#End Region
 
Namespace UpdatePanelJavaScript
 
    <Description("Creates JavaScript interface simulating UpdatePanel.Update()")> _
    <Designer(GetType(UpdatePanelJavaScriptDesigner))> _
    <ClientScriptResource("UpdatePanelJavaScript.UpdatePanelJavaScriptBehavior", "UpdatePanelJavaScript.UpdatePanelJavaScriptBehavior.js")> _
    <TargetControlType(GetType(UpdatePanel))> _
    Public Class UpdatePanelJavaScriptExtender
        Inherits ExtenderControlBase
 
        WithEvents MyTextBox As New System.Web.UI.WebControls.TextBox
        Public Event Update(ByVal Sender As Object, ByVal E As EventArgs, ByVal parameter As String)
 
        <ExtenderControlProperty()> _
        <DefaultValue("Update")> _
        Public Property ClientCommand() As String
            Get
                Return GetPropertyValue("ClientCommand", "")
            End Get
            Set(ByVal value As String)
                SetPropertyValue("ClientCommand", value)
            End Set
        End Property
 
        Private Sub UpdatePanelJavaScriptExtender_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
            MyTextBox.AutoPostBack = True
            MyTextBox.Style.Add("visibility", "hidden")
            MyTextBox.Style.Add("display", "none")
            Dim TargetPanel As System.Web.UI.UpdatePanel = Me.TargetControl
            TargetPanel.ContentTemplateContainer.Controls.Add(MyTextBox)
            Dim script As New System.Web.UI.WebControls.Label
            Dim builder As New System.Text.StringBuilder
            builder.AppendLine("<script language='javascript' type='text/javascript'>")
            builder.Append("function ")
            builder.Append(Me.ClientCommand)
            builder.AppendLine("(parameter) {")
            builder.Append("UpdatePanelJavaScript.Update('")
            builder.Append(MyTextBox.ClientID)
            builder.AppendLine("', parameter);")
            builder.AppendLine("};")
            builder.AppendLine("</script>")
            script.Text = builder.ToString
            Me.Controls.Add(script)
        End Sub

        Sub Control_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyTextBox.TextChanged
            Dim SenderControl As System.Web.UI.WebControls.TextBox = sender
            If SenderControl.Text.IndexOf("RANDOMPARAM") <> -1 Then
                If SenderControl.Text.IndexOf("RANDOMPARAM") = 0 Then
                    RaiseEvent Update(Me, e, "")
                Else
                    RaiseEvent Update(Me, e, SenderControl.Text.Substring(0, SenderControl.Text.IndexOf("RANDOMPARAM")))
                End If
            Else
                RaiseEvent Update(Me, e, SenderControl.Text)
            End If
        End Sub
    End Class
 
End Namespace

Hope this control helps and makes your life easier :) If you don't need any of the features of this extender, but only to simulate a click on a button or textbox you can use the code below.

onclick="<%= ClientScript.GetPostBackEventReference(new PostBackOptions(TextBox1, "")) %>"

The advantage of the extender is that you don’t need to add any specific button or textbox in order to cause a postback and handle it. Moreover you get a simple JavaScript function with a parameter passing to server-side, which you can use everywhere on your page.

UpdatePanelJavaScript.zip (492.89 KB)

When a user clicks on “Login” button of your login page the password and the user name will be send in plain text format. As a result any sniffer will be able to get this vital information. Below you see the data send to the server from a page containing a TextBox for user password in an UpdatePanel.

{"Password":"MyHiddenPass"}

The most popular solution is to provide a SSL certificate for a login domain containing the login page. However, this choice is a waste of money if you just want to secure the passwords of your users, but not all the page.

Let’s meet the solution; client-side MD5 encryption. In order to avoid sniffers, you can easily encrypt the user password on the client-side with a JavaScript library and post it to the server. Below is the result;

{"Password":" afb5bcf186d39b00d94917df57b9c593 "}

Now we will have an insider look at how we do this. At http://pajhome.org.uk/crypt/md5/ you can download the MD5 JavaScript library prepared by Paul Johnston. First of all, you need to add the file to your web page. We will use the hex_md5(); method of the library. The method gets a String type parameter and returns an encrypted Hex-String value back. On the example below we will use an ASP.NET AJAX Extension PageMethod to validate the password. The login button and password textbox will be inside an UpdatePanel.

      <asp:ScriptManager EnablePageMethods="true" ID="ScriptManager1" runat="server">
        <Scripts>
          <asp:ScriptReference Path="md5.js" />
        </Scripts>
      </asp:ScriptManager>
      <script language="javascript" type="text/javascript">
      function Validate()
      {
        // Get the password entered in the page
        var Pass = $get("MyPass").value;
        // Encrypte the password
        var MD5 = hex_md5(Pass);
        // Run ValidateLogin PageMethod to validate the password
        PageMethods.ValidateLogin(MD5, Done);
      }
      function Done(result)
      {
        // Alert the boolean result returned from PageMethod
        alert(result);
      }
      </script>
      <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
          <asp:TextBox ID="MyPass" runat="server"></asp:TextBox>
          <input id="BtnLogin" type="button" value="Login" onclick="Validate();" />
        </ContentTemplate>
      </asp:UpdatePanel>

On the server side, we will encrypt the text “TruePassWord” as a modal of a right password and compare it to the incoming one.

<System.Web.Services.WebMethod()> _
  Shared Function ValidateLogin(ByVal Password As String) As Boolean
    'Encoder to convert our stored Password to IOStream
    Dim encoder As New UTF8Encoding()
    'MD5 Service
    Dim MD5 As New System.Security.Cryptography.MD5CryptoServiceProvider
    'The right password
    Dim PasswordToControl As Byte() = MD5.ComputeHash(encoder.GetBytes("TruePassWord"))
    'Converting our right password to HEX
    Dim Right As New StringBuilder()
    For i As Integer = 0 To PasswordToControl.Length - 1
      Right.Append(PasswordToControl(i).ToString("x2"))
    Next i
    'Comparing the right password and the incoming one.
    If Right.ToString = Password Then
      Return True
    Else : Return False
    End If
  End Function

We are done. Hope this helps.

From the day one with AJAX we had the same problem; “Back button is not working!” AJAX caused a new experience for me, I never noticed that so many people are used to Back and Forward buttons in browsers, however browsers history can’t handle XMLHttpReuqest –no back, forward button-. As we all know there are some tricky solutions to solve this problem, nevertheless there wasn’t a complete and easy to use solution for ASP.NET developers.

And voila :) UpdateHistory control from Nikhil Kothari –Microsoft Web/ASP.NET Team Architect- solves all of our problems in a crossbrowser way. The solutions uses an hidden IFRAME for Internet Explorer (which is not needed and used for Mozilla) and changes IFRAMEs URL by adding anchors to create history data. Further on, a JavaScript timer checks for changes made by browsers Back and Forward buttons and calls additional XMLHttpRequest which can be handled in server-side. Secondly there is a built-in checker for the first time load of the page, which gives us the opportunity to use the solution as a unique URL identifier for our AJAX pages. Meaning you will have a separate URL for marked AJAX rendered pages.

The control was built by Nikhil before the release of AJAX Extension but it is updated yesterday :) Let’s see how to use it.

-First of all, download the sample application and binaries from Nikhil’s web site. The package contains some other cool controls as well, which we will not discuss at the moment. You can just check them out for further usage.

-Add the control through nStuff.UpdateControls.dll file to your toolbox and drag and drop one UpdateHistory control to your web page. This control will not be visible when the page is rendered.

-Add an event handler name for OnNavigate event of UpdateHistory. The final mark-up should be like this;

<nStuff:UpdateHistory ID="UpdateHistory1" runat="server" OnNavigate="HistoryNavigate">
    </nStuff:UpdateHistory>

-Secondly, go to your code-behind file and create your event handler. In the event handler you will get an EntryName representing which marked AJAX request is navigated in browser. We will see how to mark pages later on. In the event handler we get our EntryName, render our content and refresh the UpdatePanel. In order to get server side Update method working you need to set your UpdatePanels UpdateMode to Conditional.

    Protected Sub HistoryNavigate(ByVal sender As Object, ByVal e As nStuff.UpdateControls.HistoryEventArgs)
        Dim SelIn As Integer = 0
        If String.IsNullOrEmpty(e.EntryName) = False Then
            SelIn = Int32.Parse(e.EntryName)
        End If
        Dim InhaltControl As UserControl
        InhaltControl = Page.LoadControl("content.ascx")
        InhaltControl.Attributes.Add("ID", SelIn)
        InhaltControl.Attributes.Add("Part", "Main")
        UpdatePanel1.ContentTemplateContainer.Controls.Clear()
        UpdatePanel1.ContentTemplateContainer.Controls.Add(InhaltControl)
        UpdatePanel1.Update()
    End Sub

-Finally let’s mark pages -AJAX requests-.

        UpdateHistory1.AddEntry(e.Item.Attributes("PrimaryKey"))

We are done. That’s so easy to integrate this solution which solves all the cross browser problems as well. In addition, try to copy one of the URLs with anchors on it and past on a new browser window. You will see the page is rendered like the user has navigated to the page. This is another aspect of this cool UpdateHistory control, which provides unique URL identification feature as well.

Thanks to Nikhil Kothari for brilliant work.

Update (02/07/2006) : If you somehow get JavaScript errors in your page when you add Nikhil's control check if your project has debug=true setting in web.config. Try to set your project debug=false and see what happens. Hopefully you will get your problem solved. Actually I got no idea why this happens :(

Twitter
RSS
Youtube
RSS FeedBurner Mail Subscription Blog Search
You can find a list of all blog posts in the archive. If you still wanna do a search just click here!
Instagram Instagram Instagram