Archives

Archives / 2005 / December
  • Saving partial state of an ASP.NET control

    Rick Strahl has a created a great control that's specialized in saving other control's state. This enables you to declare what properties you really care about, which is a great improvement over ViewState and even ControlState.
    There could certainly be a few improvements, but check it out:
    http://west-wind.com/weblog/posts/3988.aspx
    UPDATE: Rick did actually improve his control based on the feedback he got and now it looks perfect:
    http://west-wind.com/weblog/posts/4094.aspx

    Read more...

  • Man literally dives from sky

    I have to admit I didn't know that.
    In 1960, before Gagarin, Joe Kittinger reached the boundary between Earth and space using a balloon. He reached the incredible altitude of 31300 meters, 3.5 times the height of Mount Everest. It's not technically space (if a ballon can sustain itself, it means that there still is enough atmosphere for it to float) but it's admittedly a fuzzy limit.
    That's fascinating in itself, but wait... Once he got there, he did the most amazing thing: he jumped. He... jumped... With a movie camera. Having jumped from a much more modest altitude, I can only begin to imagine the life-altering experience it must have been for him. Amazingly, we have images of his incredible dive.
    That day, Joe Kittinger, at the peril of his life, advanced the whole of the human kind on its way into space, and broke four records: highest balloon ascent, highest parachute jump, longest freefall and fastest speed by a man through the atmosphere at a whopping 982 km/h.
    Watch the video here: Skydiving from the edge of the world
    Seen on Nobel Intent.

    Read more...

  • Making callbacks (and Atlas) synchronous, or how to shoot yourself in the foot

    I've explained before why XmlHttpRequest should always be used asynchronously. In a nutshell, JavaScript is not multi-threaded, so the only way to keep your application and browser reasonably responsive is to use some kind of asynchronous pattern. This way, the multitasking is left to the hosting browser and the JavaScript developer can enjoy a relatively easier programming environment where he only needs to care about events and not about summoning threads and managing locks.

    It's important to note that if you click on a link in a browser, it usually doesn't freeze: the UI is still fully usable even while the request is being completed. You can still cancel it by pressing the stop button, you can access all the menus, etc.

    While there is a synchronous XmlHttp request going on, it's a different matter: the browser is completely frozen and none of the UI works. This is utterly wrong on several accounts.

    First, if the server never answers, your users will need to kill the browser (assuming they know how to do that, which they usually don't).

    Second, any UI that freezes for more than half a second without giving the user a clue about what's going on (remember the little animation that usually indicates navigation or posting back does not move during an XmlHttp request), as far as the user is concerned, just looks as if it had crashed.

    Finally, the web application should not have side effects on its container (the browser). In particular, it should not put it into an unresponsive state. I agree that the browser should not let itself be frozen by its contents, but that's unfortunately the way it is and we just have to deal with it (by the way, Firefox reacts exactly the same way as IE in this department).

    That's why callbacks in both ASP.NET 2.0 and Atlas are always asynchronous. The async parameter in the case of ASP.NET callbacks is mileading. It should really be named "parallel": when set to true, any number of callbacks may be initiated simultaneously and if false, only the last initiated will actually call back.

    That being said, I've been getting a lot of feedback lately from people who just dislike so much asynchronous programming that they want nothing to do with it (even if it's conveniently hidden from them like it is in Atlas). Well, if what you really want is to shoot yourself in the foot, who am I to argue with that? You're the customer, and I'm here to answer your demands. So here's the gun... (of course I'm kidding here. I understand why people want to use synchronous callbacks even if I personally disagree).

    Add this small script to your page (preferably in the <head> section) and all your XmlHttp requests will be done synchronously no matter what the framework you're using is doing. This works with ASP.NET 2.0 callbacks in both IE and Firefox but breaks callbacks for Opera. I suspect that it would also work with other Ajax frameworks such as Atlas.

    <script type="text/javascript">
        var __xmlHttpRequest = window.XMLHttpRequest;
        window.XMLHttpRequest = XMLHttpRequest = function() {
            var _xmlHttp = null;
            if (!__xmlHttpRequest) {
                try {
                    _xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
                }
                catch(ex) {}
            }
            else {
                _xmlHttp = new __xmlHttpRequest();
            }
           
            if (!_xmlHttp) return null;
            
            this.abort = function() {return _xmlHttp.abort();}
            this.getAllResponseHeaders = function() {return _xmlHttp.getAllResponseHeaders();}
            this.getResponseHeader = function(header) {return _xmlHttp.getResponseHeader(header);}
            this.open = function(method, url, async, user, password) {
                return _xmlHttp.open(method, url, false, user, password);
            }
            this.send = function(body) {
                _xmlHttp.send(body);
                this.readyState = _xmlHttp.readyState;
                this.responseBody = _xmlHttp.responseBody;
                this.responseStream = _xmlHttp.responseStream;
                this.responseText = _xmlHttp.responseText;
                this.responseXML = _xmlHttp.responseXML;
                this.status = _xmlHttp.status;
                this.statusText = _xmlHttp.statusText;
                this.onreadystatechange();
            }
            this.setRequestHeader = function(name, value) {return _xmlHttp.setRequestHeader(name, value);}
        }
    </script>

    Update: modified the script to include more properties of the XHR object, which makes the script compatible with ASP.NET 3.5.

    Read more...

  • Got me a 360 this morning

    Well, it seems like this second XBOX 360 shipment has finally arrived. Thanks to a tipster whose identity I shall not reveal (but absolutely no MS insider info involved), I was this morning a little before 9AM (one hour before the gates open) at the Costco in Bellingham. We were second in line with my friend David. The line was no more than 25 people when the gates opened, and they had dozens of 360s ready to grasp. Rumor has it they had 144 in Bellingham and about as many in Tumwater.

    Read more...

  • How to use enumerations in Profile?

    If you've tried to put an enum type into the ASP.NET Profile, maybe you've noticed that there's a small caveat with specifying its default value. To specify the default value, you need to use the serialized value, using the same serialization the profile is going to use for this property. For non-string types, the default serializer is XML. So if you add this to your profile section:

    Read more...

  • Google Sitemaps for ASP.NET 2.0

    Google has a little-known feature that enables web site authors to tell the search engine about the structure of their site. ASP.NET also has a way of representing the structure of the site in a map. ASP.NET SiteMaps can be exposed on the site using a Menu, TreeView or SiteMapPath control, but there is no built-in feature that exposes this information in the format that Google understands.

    That's why I've developed a small handler that scans the ASP.NET SiteMap and formats it into the Google XML format for site maps. Once you've copied this handler into your site, just register it as your site map with Google from this page:
    https://www.google.com/webmasters/sitemaps

    I've also added a very simple control that displays the ASP.NET SiteMap in a very plain HTML form (using h1...h6 tags) that is likely to be well indexed by most search engines. The control's look can be very much improved on and customized but I'll leave that as an exercise for the reader.

    The sample also comes with a sample site to demonstrate the use of the control and handler.

    Download the project from here:
    http://www.gotdotnet.com/codegallery/codegallery.aspx?id=237330e0-65c5-4ebb-b62b-e486dd598604

    UPDATE: I updated the handler so that it can now use Google-specific attributes. You can now specify additional information such as the update frequency of each page directly in the ASP.NET SiteMap (version 1.1 of the handler).

    UPDATE 2: This implementation is now obsolete. This feature is now part of the ASP.NET Futures release with a much more complete implementation. Check it out!
    http://www.asp.net/downloads/futures/default.aspx?tabid=62

    UPDATE 3: I've added back the source code as an attachment for this post, for reference purposes (but I encourage everyone to use the Futures version).

    Read more...

  • Why no synchronous call support in Atlas?


    _keyDownHandler = Function.createDelegate(
    this, this.onKeyDown);

    Here, I'm setting the private variable _keyDownHandler (a private variable is a variable declared inside the body of a function/class) to point to the onKeyDown class method. When the delegate is called, it will run within the context of the particular instance that created it and will have access to all its instance properties and methods. Hence, there is no need for global variables. createCallback similarly enables you to create a reference to a function that will remember the arbitrary context object you passed it at creation-time when it is finally called.
    If you need to know the result of the call before allowing the user to continue, you shouldn't block the whole browser. What you should do is disable the pieces of UI that should remain untouched while the call is going on (which means other parts of your app can continue to run in the meantime) and re-enable them when the call completes. You can see an example of how to do this declaratively in this blog post:
    http://weblogs.asp.net/bleroy/archive/2005/09/20/425698.aspx
    Asynchronous calls actually become very natural and transparent in a declarative and event-driven environment such as Atlas is providing.
    You may think asynchronous calls are more difficult, but unfortunately until the browsers become multitasking scripting environments (which is not something likely to happen in the foreseeable future imho), they are the only way to create a responsive client web application.

    Read more...

  • ASP.NET Alerts: how to display message boxes from server-side code?

    One of the most common mistakes beginner ASP.NET developers make is to call MsgBox.Show from their ASP.NET server-side code. It is a mistake because this code runs server-side and will just display the message box on the server where it's not going to be very useful. Well, in version 2.0, it will actually throw an exception.

    Once the developers understand the disconnected way HTTP works, it becomes quite natural, but the need to trigger an alert box from the server-side remains.

    That's why I just published a new GotDotNet workspace CodePlex project that contains an Alert server control and a ConfirmButton server control that you can use both client-side and server-side. The controls should work fine in all browsers, but will look a little nicer in IE thanks to the (non-standard) modal dialog feature.

    Here's how you use the controls...

    First, if you want to show an alert from server-side code, you've got to first declare the alert in your page's markup (or new up a new Microsoft.Samples.Alert.Alert control and set its properties and subcontrols if you're that sort of developer):

    <ms:Alert ID="ServerAlert" runat="server" Buttons="OK" Title="Server Alert" OnChoice="ServerAlertChoice"
     
    Font-Names="Arial" HorizontalAlign="Center" Width="350px" Height
    ="100px">
     
    This is a rich alert box that was triggered by<br /><i>server-side code</i>.<br
    />
    </ms:Alert>

    And then simply call the Show() method on the Alert instance from server-side code:

    ServerAlert.Show();

    You can handle the user's choice server-side by handling the OnChoice event and act accordingly:

    public void ServerAlertChoice(object sender, AlertChoiceEventArgs e) {
      AlertResult.Text =
    "You clicked "
    + e.Result.ToString();
      AlertResult.Visible =
    true
    ;
    }

    You can also trigger the alert's display client-side and handle its response client-side:

    <ms:Alert ID="ClientAlert" runat="server" Buttons="YesNoCancel" Title="Client Alert"
      Font-Names="Arial" HorizontalAlign="Center" Width="350px" Height
    ="140px">
      This is a rich alert box that was triggered by<br /><i>client-side code</i>.<br
    />
      The button will take the value that you chose.<br /><br
    />
    </ms:Alert
    >
    <input type="button" name="ClientShowButton" value
    ="Show alert without posting back"
     
    onclick="this.value=<%= ClientAlert.GetShowClientEvent() %>;" /><br />

    Or any combination that's useful for you.

    You can also use the ConfirmButton as you would use a regular button (it derives from Button) to ask the user for confirmation before posting back to the server:

    <ms:ConfirmButton ID="Confirm" runat="server" OnClick="ConfirmClick"
     
    Text="Confirm Button" ConfirmText="Are you sure you want to press this button?" />

    And so that you can use such confirm buttons in a repeated control such as a GridView, instances of a repeated confirm button can reference a single alert to save HTML rendering and not repeat the alert text for each data row:

    <asp:GridView AutoGenerateColumns="False" DataSourceID="Datasource1"
      
    ID="GridView1" runat="server" DataKeyNames="ID">
     
    <SelectedRowStyle BackColor="gray" />
     
    <Columns>
       
    <asp:BoundField DataField="ID" HeaderText="ID" InsertVisible="False" ReadOnly="True"
         
    SortExpression="ID" Visible="False"/>
       
    <asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name"/>
       
    <asp:BoundField DataField="Alias" HeaderText="Alias" SortExpression="Alias"/>
       
    <asp:TemplateField HeaderText="Command">
         
    <ItemTemplate>
           
    <ms:ConfirmButton ID="Confirm" runat="server"
             
    Alert="GridSelectConfirmAlert" CommandName="select"
             
    Text="Select" /><br />
         
    </ItemTemplate>
       
    </asp:TemplateField>
     
    </Columns>
    </asp:GridView>

    <ms:Alert ID="GridSelectConfirmAlert" runat="server" Buttons="YesNo" Title="Are you sure?"
     
    Font-Names="Arial" HorizontalAlign="Center" Width="320px" Height="50px">
     
    Are you sure you want to select this row?
    </ms:Alert>

    Check out the Alert.aspx page for these examples in context.

    I hope this is useful. As always, feedback is welcome.

    http://www.codeplex.com/alerts

    UPDATE: The first release was missing a file. I've corrected the version in source control and the release file. Thanks for pointing that out.

    UPDATE 2: the project migrated to CodePlex.

    UPDATE 3: Since I wrote this, many things happened, such as Ajax becoming mainstream. You might want to try this extender from the Ajax Control Toolkit: http://www.asp.net/AJAX/AjaxControlToolkit/Samples/ConfirmButton/ConfirmButton.aspx

    Read more...