Ajax AutoComplete Extender with WCF

blackstone

The problem with conjuring tricks is that they lose practically all their glamour once you find out how they are done.  It’s very cool to see David Blaine walk down the street, do a few passes over his hand, and resurrect a fly which proceeds to flee.  It’s rather disappointing to do a google search and discover that in order to prepare for this trick, the first requirement is that you freeze a fly.

My trick is to make an autocomplete extender from the Ajax Control Toolkit call a WCF service instead of an asmx service.  For this recipe, I assume that you are already familiar with the autocomplete extender, and that you are using Visual Studio 2008.  I warn you in advance — my trick disappoints.  It is so trivially easy that, once the technique spreads, it is very unlikely to impress your colleagues at work, much less get you a date with a supermodel.

Start by creating a new web project called AutocompleteWCF.  Add a reference to the AjaxControlToolkit.dll.  Open up the default aspx page that is generated with your project, and add the following code to:

    <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>
    <div>
            <asp:TextBox runat="server" ID="myTextBox" Width="300" autocomplete="off" />
            <ajaxToolkit:AutoCompleteExtender
                runat="server" 
                BehaviorID="AutoCompleteEx"
                ID="autoComplete1" 
                TargetControlID="myTextBox"
                ServicePath="Autocomplete.svc" 
                ServiceMethod="GetCompletionList"
                MinimumPrefixLength="0" 
                CompletionInterval="1000"
                EnableCaching="true">
            </ajaxToolkit:AutoCompleteExtender>
    </div>
    </form>

 

This is the standard demo code that is shipped with the Ajax Control Toolkit Sample Website.  I’ve simplified it a bit by removing the animations.  The only significant change I’ve made is to change the ServicePath from Autocomplete.asmx to Autocomplete.svc, the latter being the extension for a WCF service.

The next step is to create our service and add a GetCompletionList operation to it.  The easiest way to do this is to go to Add | New Item and just select the Ajax-enabled WCF Service item template, but this would be so easy that it is hardly worth doing.

Instead, create a new WCF Service using the WCF Service Item Template and call it Autocomplete.svc.  Visual Studio will automatically generate a service interface for you.  Delete the interface.  We don’t need it.  (To be more specific, I don’t know how to get this to work with an interface, so I’m just going to ignore that it is possible.)

Again, I am going to rip off the ACT sample app and just borrow the code from their webservice and place it in our WCF service.  The WCF service class (Autocomplete.svc.cs) will look like this:

    [ServiceContract(Namespace = "")]

    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]

    public class Autocomplete

    {

 

        [OperationContract]

        public string[] GetCompletionList(string prefixText, int count)

        {

            if (count == 0)

            {

                count = 10;

            }

 

            if (prefixText.Equals("xyz"))

            {

                return new string[0];

            }

 

            Random random = new Random();

            List<string> items = new List<string>(count);

            for (int i = 0; i < count; i++)

            {

                char c1 = (char)random.Next(65, 90);

                char c2 = (char)random.Next(97, 122);

                char c3 = (char)random.Next(97, 122);

 

                items.Add(prefixText + c1 + c2 + c3);

            }

 

            return items.ToArray();

        }

 

A few things worth noting:

1. Autocomplete does not implement the IAutocomplete Interface.  Even though this is generated automatically, with the WCF Service item template, you should remove it.

2. The service contract has a blank Namespace explicitly declared. 

3. The ASPNetCompatibilityRequirements attribute must be added to our class.

 

This takes care of the code that calls the WCF service, as well as the service itself.  We now have rig up the web.config file.  If you’ve been working with WCF for any length of time, then you know that this is where the problems usually occur.  Fortunately, the configuration is fairly simple.  You need to set up an endpoint behavior for your service that enables web scripting (much the way asmx web services must be decorated with the ScriptService attribute in order to be called from client-script).  You also will need to turn AspNetCompatibilityEanbled on for the hosting environment.

 

    <system.serviceModel>

        <behaviors>

            <endpointBehaviors>

                <behavior name="AjaxBehavior">

                    <enableWebScript/>

                </behavior>

            </endpointBehaviors>

        </behaviors>

        <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>

        <services>

            <service name="AutocompleteWCF.Autocomplete">

                <endpoint address="" behaviorConfiguration="AjaxBehavior" binding="webHttpBinding" contract="AutocompleteWCF.Autocomplete"/>

            </service>

        </services>

    </system.serviceModel>

 

And that is all you need to do make the AutoComplete Extender work with a WCF service instead of an asmx web service.  I told you it would be unimpressive.

Of course, using a WCF service for Ajax has all the limitations that using an asmx file for Ajax did.  First of all, you can’t call a service that is in a different domain than the page which hosts your client-code.  This is a security feature, to prevent malicious code from redirecting your harmless javascript to something nasty on the world wide web.

Second, you can’t call just any service from your client-side code.  The service must be explicitly marked as something that can be called from client code.  In asmx web services, we used ScriptService for this.  In WCF services, we similarly use EnableWebScript binding property.

Now I feel like I’ve wasted your time, so here’s a YouTube video of David Blaine to make up for it.  And remember, David Blaine is to Chris Angel what Daisy Duke was to Alexis Carrington.  It’s an existential thing, and at some point, you’ve just got to pick sides and stay put in a way that will determine who you are for the rest of your life.

Are you a David Blaine/Daisy Duke kind of person or are you a Chris Angel/Alexis Carrington sort?  Do some soul searching and please let me know what you learn about yourself.

Fingerprint Scanner Interferes with Media Player Extender

fingerprint

Microsoft has a technology called Media Center Extender that basically allows you to use your XBOX 360 as a media center.  All that’s required is that you have a computer connected to your XBOX over a network with the Media Center software installed (it comes standard with Vista Premier) and turned on.  The XBOX can then be used to play movies and music files located on your harddrive.

I haven’t looked at this much until recently, when I found out about vmcNetFlix.  vmcNetFlix is one of those great ideas.  The developer saw that NetFlix was allowing subscribers to download movies to their desktops, and that Microsoft was allowing people to stream movies to their TV’s through an XBOX, and he put in the final pieces to connect all of this together.  vmcNetFlix has its issues at times, but hey, it’s one guy providing a solution on his own time and it’s free.

Before I could get any of this working, however, I had to get my very sweet HP entertainment laptop to talk to my XBOX, and kept running into the same issues with the XBOX complaining that it could not connect the media center extender to my laptop, despite my repeated attempts to reboot both systems and clear out caches and certificates and blowing on both ends of my ethernet cable for no particular reason except that some guy on some newsgroup told me to.

Finally, based on another internet tip, I uninstalled the nice biometric software that came with my laptop and everything started working.  For whatever reason, every piece of biometric software, which allows you to scan in your fingerprint to identify yourself to the operating system rather than type in a password, interferes with Media Center.  I was using DigitalPersona, but it appears that the problem is not unique to them.

So now the fingerprint scanner on my laptop doesn’t do anything.  This is because it turned out to be a technological bottleneck.  On the other hand, I can now stream movies, including BlueRay movies, to my HD TV anytime I want using free technology built in someone’s basement that removes bottlenecks.  Is it worth it?

Well, yes. Not only can I watch any episode of Buck Rogers in the 25th century whenever I want, but I’ve also got most of the Werner Herzog and Rainer Werner Fassbinder catalogs ready for instant streaming.  That’s hot.  That’s Erin Grey hot.

Extending the Ajax Control Toolkit Tab Container with Lazy Loading

multi-tabs

 

download source code

ASP.NET has been missing a good, free tab control for a long time.  With the ACT Tab Container, we were finally given one.  It typically runs in client-side only mode, but can interact with server-code if we set its AutoPostback property to true.

Compared to what we had before, it is a huge improvement.  The peculiar thing about it, however, is that it isn’t actually an Ajax control.  It doesn’t use asynchronous postbacks or web service calls to talk to the server — instead you just have these two mode: run it using client script only, or run it using server-side events and code-behind only.

So a few months ago I rectified this for a project, and only found out afterwards that Matt Berseth had already outlined the technique on his blog.  You basically run the tab container in client-side mode, and add update panels to the tab panels that you want to be ajaxy.  You then hook up the client-side ActivePageChanged event in such a way that it spoofs the Update Panel contained in the tab, causing an asynchronous (or partial) postback.

Matt also gave this technique a cool name.  He called it ‘lazy loading the tab panel’.  Like lazy loading in OOP, using this technique the update panels inside each tab panel only do something when its tab is selected.  Information is loaded only when its needed, and not before.

I must admit that I hold some resentment against Matt for coming up with this first, and for coming up with the cool moniker for it.  On the other hand, the solution I came up with encapsulates all of the javascript needed for this into a nice simple extender control that you can drop on your page, which his does not, and I’m rather proud of this.

The VS 2008 project for this extender is linked at the top of this post.  To use it, you need to compile the project and add the compiled assembly to your project, or else just add the project to your solution and add a project reference.

1. Drop the TabContainerExtender control into your page.

2. Set the Extender’s TargetControlID property to your TabContainer’s ID.

3. In the RegisterUpdatePanels element of the Extender, map your tabs to your update panels.  This mapping tells the extender which Update Panels to activate when each tab is selected.

Your markup will look something like this:

    <cc2:TabContainerExtender ID="TabContainerExtender1" 
    runat="server" 
    TargetControlID="TabContainer1" OnActiveTabChanged="ActiveTabChanged">
    <RegisterUpdatePanels>
    <cc2:UpdatePanelInfo TabIndex="0" UpdatePanelID="UpdatePanel1" />
    <cc2:UpdatePanelInfo TabIndex="1" UpdatePanelID="UpdatePanel2" />
    <cc2:UpdatePanelInfo TabIndex="2" UpdatePanelID="UpdatePanel3" />
    </RegisterUpdatePanels>
    </cc2:TabContainerExtender> 

4. If you want to add some code-behind to your active tab changed event, add set the OnActiveTabChanged property of the Extender to the name of your handler.  The thrown event will pass the correct Index number for the active Tab, as well as the ID of the mapped Update Panel.  The handler’s signature looks like this:

        protected void ActiveTabChanged(int index, string panelID)

        {

            …

        }

I highly encourage you to read Matt Berseth’s blog entry (which I have to admit is pretty good) to get a clear idea of the techniques being applied in this ajax extender.  If you just need a quick solution, however, feel free to download this code from the link at the top and use it any way you like with no strings attached.  There is a sample project attached to the solution that will demonstrate how to use the Tab Container Extender, in case you run into any problems with lazy loading your panels.

For reference, here is the code for the sample implementation, which loads controls on the fly based on the tab selected:

    <cc1:TabContainer ID="TabContainer1" runat="server">
    <cc1:TabPanel ID="TabPanel1" runat="server" HeaderText="Tab Panel 1">
    <ContentTemplate>
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
        Content 1 ...
        <br />
            <asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>      
        </ContentTemplate>
        </asp:UpdatePanel>    
    </ContentTemplate>
    </cc1:TabPanel>
        <cc1:TabPanel ID="TabPanel2" runat="server" HeaderText="Tab Panel 2">
    <ContentTemplate>
        <asp:UpdatePanel ID="UpdatePanel2" runat="server">
        <ContentTemplate>
        Content 2 ...
        <br />
            <asp:PlaceHolder ID="PlaceHolder2" runat="server"></asp:PlaceHolder>      
        </ContentTemplate>
        </asp:UpdatePanel>    
    </ContentTemplate>
    </cc1:TabPanel>
        <cc1:TabPanel ID="TabPanel3" runat="server" HeaderText="Tab Panel 3">
    <ContentTemplate>
        <asp:UpdatePanel ID="UpdatePanel3" runat="server">
        <ContentTemplate>
        Content 3 ...
        <br />
            <asp:PlaceHolder ID="PlaceHolder3" runat="server"></asp:PlaceHolder>      
        </ContentTemplate>
        </asp:UpdatePanel>    
    </ContentTemplate>
    </cc1:TabPanel>
    </cc1:TabContainer>
    <cc2:TabContainerExtender ID="TabContainerExtender1" 
    runat="server" 
    TargetControlID="TabContainer1" OnActiveTabChanged="ActiveTabChanged">
    <RegisterUpdatePanels>
    <cc2:UpdatePanelInfo TabIndex="0" UpdatePanelID="UpdatePanel1" />
    <cc2:UpdatePanelInfo TabIndex="1" UpdatePanelID="UpdatePanel2" />
    <cc2:UpdatePanelInfo TabIndex="2" UpdatePanelID="UpdatePanel3" />
    </RegisterUpdatePanels>
    </cc2:TabContainerExtender> 

How to Read a Tech Book

johnnymnomonic

My efforts to write about learning Silverlight in Seven Days are filled with omissions and gaps.  While each Silverlight "day" really does constitute one day’s worth of studying, they haven’t been contiguous days.  One large gap is due to a trip I had to make to Washington D.C. to settle personal affairs.  Others were job related since, like most of you, I have to maintain my day job even as I’m expending effort to learn new technology in my off time — which, however, will eventually feed back into my day job.  Which invites the obvious question of whether learning technology is really work time or private time.  I tend to think of it as private time, since I enjoy it immensely and grow personally by doing it.  All the same — and I believe this is not the case in most IT shops — my day job is actually forward looking about this sort of thing, and allows me to spend part of my day learning all the new acronyms coming out of Redmond — in some sense paying me to do something I love.  But an equally valid way of looking at it is that I am working to keep my IT shop informed about the best solutions for its upcoming projects, and the reward for the investment of time and energy I make in learning these technologies are ultimately reaped by my company.  I am, in effect, investing my company’s time wisely.

Should we choose to look at the matter in this way, then it is important that the time spent on learning technology be used optimally.  This is hampered by the fact that information about things like WCF, WPF, WF (the initial "W" is typically truncated, I assume, because it evokes notions of profession wrestling) and Silverlight are poorly disseminated.  Half of the effort spent on learning new tech involves tracking down the proper resources, weeding out the unhelpful books that misstate what they can offer and the ones that are just poorly written or misinformed, and finding the correct location for the online resources — including source code — that one needs.  Scott Galloway has a great post about this problem over on his blog: http://www.mostlylucid.net/.

The other half is spent actually engorging all the information that is available.  There is a scene from Johnny Mnemonic, that peculiar 1995 Keanu Reeves sci-fi vehicle, in which Keanu uploads 300 megabytes of data into his cerebral cortex.  In order to prepare for it, he puts a bite guard in his mouth, clamps down and, with evident consternation on his face, yells out "hit me."  This is how I feel whenever I prepare myself to sit down with a tech book.

A tech book is not a friendly beast.  You cannot curl up with it in bed.  You never giggle over a clever turn of phrase and beg your partner to allow you to read her a passage aloud.  Instead, it is a big heap of bound paper, generally printed in large type in an apparent attempt to make it seem weightier than it has any right to be, which you have to plow through in a Sisyphusian effort to reach the end.  In truth, no one ever gets to the end of one of these things because we all get bogged down in the details.  This is natural enough, because the presentation is typically all about the details after the initial chapter, and the initial chapter tends to alternate between vagueness and hello world samples to the point that it just can’t be taken very seriously.  But then we get lost in the details.  There is so much we don’t understand in reading through these tech books that we become frantic over the thought that we might be missing something important — the key that unlocks all the material we are trying to absorb.  The reading process becomes slower and more onerous until finally external affairs draw us back into the life-world or we throw our tech book to the wall where, with luck, it shatters into a million pieces and we never have to pick up reading again where we left off.

Scott Hanselman touches on this point in his post: Books: We Need More So What, Now What, And What For And Less Just What, though it might just as easily have been titled, "Why Tech Books Suck".  The essential problem with tech books is that they never work out the inherent paradox of all learning: one cannot learn the whole without understanding the parts; one cannot know the parts without understanding the whole.  In contemporary exegetics, this known as the hermeneutic circle.

Aristotle says in his Poetics that tragedies such as Oedipus Rex and Electra are higher and more philosophical than historical works because they aspire to truth, whereas histories merely offer details.  I think it is this desire to know the "truth" of a technology — its purpose, its potential, it’s meaning — from a medium so poorly suited to this task, the tech book, that typically leaves us feeling so frustrated and so drained.  We get bogged down in details because tech authors get bogged down in details, and it is the exceptional writer who knows how to navigate the hermeneutic circle in order to provide us with a usable tech book — the criterion for usability, in this case, being merely not making us want to throw it across the room.

The quality of tech books is out of our control, however, so we must turn to the quality of reading tech books.  Here are my suggestions for how to get the most out of a tech book, so that as little time is wasted on them as possible:

1. Read Online — I use Safari Books Online for my tech education, as well as MSDN and various tech blogs.  This tends to make my eyes bleed, but it has the distinct advantage of not lulling me into the illusion that tech books are like other books.  Once I start treating tech books like other books, I find that I fall into the habits I’ve acquired for reading fiction and even most non-fiction.  I look for a plot and my mind tries to work itself towards a narrative climax that never actually transpires.  Tech books don’t have plots.  They just are.  If you rip out the chapters and put them together in a different sequence, it generally doesn’t matter.  Tech books are heaps, not paths.  Reading online helps me to avoid this confusion — though it obviously isn’t for everyone.

2. Plan to Re-read — if you set out on a new book knowing that you will re-read it, then you won’t get so bogged down in the details.  You can always go back and pick up what you missed later.  I generally read a tech book three times.  The first time I just skim through the chapter headings so I know what the book is going to cover and what I feel confident about skipping entirely.  This can be done in a few minutes.  On the second read, I just skim the whole book.  I don’t try to do any coding exercises.  I just get a good grasp of the principles involved, and the various materials I will need to understand.  The goal is simply to get to the end of the book, not to understand it in its entirety.  This can be done in a few hours.  The third read is used to go back and pick up the important stuff.  From the second read, I know that there are things I don’t understand, and hopefully I will have formed an opinion of what is important in the book and what is drivel.  In the third read, if a third read is even necessary, I pick up the important bits.

3. Give Yourself Permission to Skip — The fear of missing something important is a paralyzing fear.  You have to give yourself permission to skip things when you are reading a tech book.  Remember, a lot of the things in a tech book are just filler.  The author felt he had to push something in that is actually irrelevant, or the publisher has established a page count for him that he must fulfill.  Not everything in a tech book is important.  Marshall McLuhan developed a habit of reading only the right hand pages of any non-fiction book (he would read a non-fiction book in its entirety, however).  The way he explained it, a lot of non-fiction is just filler, and by his estimation, only 10% or so of any non-fiction book was actually worth knowing — and that was if it was a good book.  An intelligent person can fill in the gaps as he goes along.  More importantly, the way your mind fills in these interstitial gaps actually helps it to retain information better.  The mind learns not by simply replicating what it finds in a book, like some copying machine, but rather by trying to reconstruct and build things in the imagination.  In rhetoric, this is sometimes called an enthememe, or a logical argument with gaps.  The ancient orators discovered that by not completing a logical argument, but rather by letting an audience piece it out for themselves, they were better able to convince the audience of the rightness of their conclusions.  Laying things out for people leaves them unconvinced.  Making them work things out for themselves gives them possession of the information, and allows them to make it their own.

4. Talk About What You Learn — Reading a book is useless if you can’t retain what you’ve learned.  The best way to retain the information in a tech book is to use it.  Unfortunately we aren’t always afforded opportunities to use what we know.  We do, however, always have outlets to talk about what we know, and the process of talking not only forms new neural pathways in our brains, thus increasing retention, but allows us to correct our mistakes and misconceptions.  Talking to other developers working on the same technology is optimal.  If that is not possible, however, blogging or writing to newsgroups can serve the same function.  They keep the technology ever in your mind, and you can add on to it or take away from it as you go along.

All of this may be pretty obvious, but then one would think that figuring out how to write better tech books should also be pretty obvious — and it isn’t.  Learning new technologies is generally considered one of the "soft" problems of IT.  By now, however, we have all had enough industry experience with reading tech books that it is clear this is not the case, and it is probably time to throw tech books onto the mound with all of the other "hard" problems of IT, like how to retain good people and how to complete a project on time.

Antivirus Software Blocks Outgoing Mail

general

I use Windows Live Mail to access my Comcast email account.  Whenever I try to send emails, I get this lovely message:

A TCP/IP error occurred while trying to connect to the server.

Subject ‘Re: REQUEST FOR URGENT BUSINESS RELATIONSHIP’
Server: ‘smtp.comcast.net’
Windows Live Mail Error ID: 0x800CCC15
Protocol: SMTP
Port: 25
Secure(SSL): Yes

Normally I wouldn’t care, but in this case there is a former general’s widow in Nigeria who wants to offer me a lucrative business proposal.  I can’t go into details, of course, but it is basically a sure-fire thing, and the only thing now preventing from being a very wealthy man is this problem with sending emails to Comcast’s SMTP server.

The problem turns out not to be on Comcast’s end, however.  My problems with Comcast typically involve billing and service interruption, not basic technology.  Consequently, I began looking elsewhere to track down the issue.

The culprit turns out to be my virus scanning software.  There are lots of posts on the Internet claiming that it is the email scanner which muffs up sending.  This is a red-herring, and turning off virus scanning for your emails is, all things considered, not such a great notion.  It also doesn’t really make much sense — why would scanning incoming emails prevent the sending of emails?

I did a little more investigating and found this McAfee log file, which reveals what is really going on.

4/5/2008    12:04:39 PM    Blocked by port blocking rule     C:\Program Files\Windows Live\Mail\wlmail.exe    Anti-virus Standard Protection:Prevent mass mailing worms from sending mail    76.96.30.117:25
4/5/2008    12:14:01 PM    Blocked by port blocking rule     C:\Program Files\Windows Live\Mail\wlmail.exe    Anti-virus Standard Protection:Prevent mass mailing worms from sending mail    76.96.30.117:25

 

Ho ho.  McAfee is blocking my port 25, purportedly to prevent zombies from taking over my machine and sending out spam messages.  Which makes perfect sense, since if I can’t send out emails, then a zombie impersonating me on my own computer will also not be able to send out emails.  It’s a let’s bomb them all and let God sort out the emails sort of solution — effective, but somewhat heavy handed.

So, with your permission, I’m going to disable my anti-virus software’s port 25 blocking.  I’m not sure of the ultimate impact upon humanity, but it would be rather convenient for me.

Some of my favorite blogs have closed down over the years due to the difficulty of maintaining a high quality blog — Teju Cole, Heaven Tree, Varieties of Unreligious Experience, Giornale Nuovo.  If mine goes down in the near future, however, you will know that it is due not to the high quality of the writing — which happens not to be one of its virtues, I fear — but rather to the incredible wealth that has fallen into the author’s lap.  I’ve read many sad final posts over the past year, but mine shall certainly be a felicitous one: this blog has closed down because the author moved into a higher tax bracket!

Thank you, thank you my anonymous Nigerian general’s widow.  And a pox upon McAfee, whose spam blocker almost prevented me from concluding this fortuitous enterprise.

Install Visual Studio 2008 beta without a DVD Burner

I had a weird problem with my DVD player, such that while I was able to burn the Visual Studio 2008 image successfully, I was not able to use it to install.  Instead, the DVD would just lock up my XP operating system.  So I resorted to my backup plan, which involved simply mounting the image as if it were a media device and running the install from there.

I was able to do this using free software provided by Microsoft called the XP Virtual CD Control Panel.  But first, a public service message: beta software such as Visual Studio 2008 should not be installed on a production machine since it is not supported.  Likewise, the Virtual CD Control Panel is unsupported, by which I mean if you have problems with this you can’t call Microsoft for help, and should be installed at your on risk.

With that out of the way, the Visual Studio 2008 (Orcas) beta image file can be downloaded here, while the Virtual CD software can be gotten here.  The Virtual CD download is a executable zip file, which you should unzip to an easily accessible location on your harddrive.  It includes the VCdControlTool executable, a readme file, and a file called VCdRom.sys.  Copy VCdRom.sys file to your system32\drivers directory.

VCdControlTool

  1. Run VCdControlTool.exe
  2. On the first run, the driver will not have been loaded yet, so click “Driver control”, click “Install Driver”, navigate to the %systemroot%\system32\drivers folder, select VCdRom.sys, and click Open. Click “Start”. Click OK.
  3. Click “Add Drive” to add a drive to the drive list. Ensure that the drive added is not a local drive. If it is, continue to click “Add Drive” until an unused drive letter is available.
  4. Select an unused drive letter from the drive list and click “Mount”.
    Navigate to the directory to which you downloaded the OrcasBeta2VSTSX1394647.img image file.   In your dialog window, change the “files of type” option to All files (“*”). Now you should be able to see the Visual Studio 2008 image file. 
  5. Select the image file and click “OK”.  (You can leave all the option check boxes unselected.)
  6. Return to your windows browser, where you should find the image file under Devices with Removable Storage.  Double click it to begin the install.

orcasinstall

Session Expired Monitor with ASP.NET AJAX

timeout

code download

Sessions are a way of preserving information on a web site between page hits, allowing the programmer to emulate a stateful application when, in fact, web pages are not really stateful.  They are also one of the banes of web development, since sessions eventually timeout when there is no interaction between the user and the web app for a prolonged period of time.  In ASP.NET, this period has a default of 20 minutes, which is really hardly enough time to pick up a donut, refill one’s coffee, and chat with fellow workers before returning to one’s computer.  What this often means is that the user, upon returning to their computer and continuing work after a 20 minute break will find that all of the data entry they have been doing has been lost.  Worse, strange errors will begin to appear in his web browser if the loss of a session is not handled gracefully. 

The most common workaround is to increase the session grace period, called the session timeout.  This is set in your web.config file, and typically looks like this (the timeout period is measured in minutes):

  <system.web>
    <sessionState
      mode="InProc"
      cookieless="false"
      timeout="20"
     />
  </system.web>

A second way of handling this is to add extra code to an app that keeps the session state alive even if the user isn’t doing anything.

A third, and the most common, way is to provide code that redirects a user to a “session expired” page if they try to interact with a web page for which the session has timed-out.  This can be a bit awkward, however, since it is a passive solution that can cause the user some dismay as they hit a submit key only to be taken to a completely unexpected page.

This post deals with an active approach to the same problem.  When the user’s session has expired, it will generate a popup message in the user’s browser window letting him know that he has been inactive for too long.  Additionally it can redirect the browser to a new page with a warning message letting him know what happened.  The user still loses all of his work, of course, but at least this way he knows what happened when he returns to his desk following his coffee break.

This solution uses three tricks.  One is the event model for Master Pages in ASP.NET:  whenever a Content Page is refreshed, its OnLoad event is called,  along with the OnLoad events of the Master Page and any user controls hosted by either the Content Page or the Master Page (the actual order of these events is 1. controls on the Master Page, 2. controls in the Content Page, 3. the Master Page and finally 4. the Content Page).

The second trick is the way ASP.NET Extensions Timer control gets reset.  This is done simply by setting the interval to a new value.  Every time the interval is set to a new value, or even the same value, the countdown on the timer begins again.

The third trick is that the session timeout one sets in the web.config file can be read programmatically simply by querying a property of the Session object.

Putting all of this together, one can build a web user control that simply sits on a Master Page and knows when the user session is ready to expire.  It resets itself to the full timeout period any time a Content Page is refreshed.  when the session expires, the user control can raise an informative message, redirect to another page, or, potentially, simply extend the session timeout (not covered here, but easy to do if you are interested).

A user control to monitor the session timeout is included in the code sample linked at the top of this post.  Here is how you can build your own.

Session Timeout Monitor Recipe:

Ingredients:

  • One Master Page
  • One User Control
  • An Update Panel
  • An ASP.NET Ajax Extensions Timer
  • A Panel control
  • A Button control

1. Create a new User Control in your project. 

2. Drop an Update Panel on the User Control and set its mode property to “Always”.

3. Add an Extensions Timer (not to be confused with the Futures TimerControl) to your project, dropping it in the Update Panel.  Name it TimerTimeout.

Normally, this configuration of the timer control and a conditional update panel is used to refresh a portion of a web page on a regular schedule, for instance in order to create a self-updating clock display.  In this case, however, the timer and update panel are used simply to trigger a notification that the session has expired. 

4. In the User Control’s code behind, add the following lines to the OnLoad event:

        protected void Page_Load(object sender, EventArgs e)
        {
            int milliseconds = 60000;
            TimerTimeout.Interval = Session.Timeout * milliseconds;
        }

This event will be called any time a content page is refreshed.  Whenever this happens, the code inside the event handler resets the AJAX Extensions Timer control to the full session lifespan as set in the web config file, in effect making the timeout for the Timer match the timeout for the session.

Since the Timer control’s Interval property is measured in milliseconds, while the session.Timeout is measured in minutes, a conversion factor of sixty thousand must be used to translate one time period into the other.

To finish this notifier, the Timer’s Tick event needs to be handled.  The Tick event gets called when the Timer’s Interval finally runs out.  In this implementation, the Tick event can either generate a popup message or cause a page redirect.

5. Place a Panel inside the Update Panel.  Set its Visible property to false.

6. Write a simple message inside the Update Panel, such as “Your session has expired.”

7. Drop a Button inside the Panel.  This Button will be used to allow the user to hide the popup message.

8. Add a public property to the User Control called SessionExpiredRedirect:

        private string _sessionExpiredRedirect;

        public string SessionExpiredRedirect
        {
            get { return _sessionExpiredRedirect; }
            set { _sessionExpiredRedirect = value; }
        }

This will be used to set the web page to which the Timer will redirect the user upon session timeout.  If no value is set, a popup message will appear, instead.

9. Handle the Timer’s Tick event:

        protected void TimerTimout_Tick(object sender, EventArgs e)
        {

            if (!string.IsNullOrEmpty(SessionExpiredRedirect))
            {
                if (SessionExpiredRedirect.IndexOf("~")==0)
                    Response.Redirect(
                        VirtualPathUtility.ToAppRelative(
                        SessionExpiredRedirect));
                else
                    Response.Redirect(SessionExpiredRedirect);
            }
            else
                this.PanelTimeout.Visible = true;
        }

This handler checks to see if a value has been set for the SessionExpiredRedirect property.  If not, it makes the Panel control inside the Update Panel visible.

10. To make the Panel control truly popup, set its CssClass property to “timeoutMessage”.  Add the following css style to the page.

<style type="text/css">
.timoutMessage
{
    position:absolute;
    top:100px;
    left:200px;
    background-color:#F5F7F8;
    border-style:groove;
    border-color:Navy;
    padding:15px;
}
</style>

11. Finally, compile this User Control and drag it on to the Master Page.  In design mode, the user control will display a misleading exception message.  Just ignore it.

12. Make sure the Master Page includes an ASP.NET AJAX Script Manager component.

This completes the recipe.  Any Content Page in this project will now automatically include the timeout monitor you have built.  Cookies are optional: this recipe will work with a session managed either with cookies or in cookieless mode.  It will only work if the session mode is InProc.

Garnish with buttered radishes.  Serve at room temperature.

(Code snippets formatted using manoli.net.)

C Sharp’s Double Question Mark Operator Recipe (??)

riddler

At a recent Microsoft conference, the presenter did some quick programming that raised a gasp of excitement from the audience (I kid you not).  He inserted two question marks in a line of code as if they were an operator and Intellisense did not protest.

“Is that a new language feature in .NET 3.5?”, a member of the audience asked.

The presenter looked somewhat puzzled.  “No, it’s in 2.0.” 

At which point half the audience suddenly realized that this was a secret 2.0 feature they could now use to impress friends and colleagues, while the other half smiled knowingly because they had been using it for over a year.  Such is the way programmers distinguish the wheat from the chaff.

So, if you aren’t using the Null Coalesce Operator, yet, you should.  It is basically a syntactic device for setting a default value for nullable types.  The ?? Operator is the equivalent of the ISNULL function in T-SQL, or the NVL function in PL-SQL, and is very handy when you are trying to translate database values into your business classes.

If, for instance, you have a nullable number type in your Oracle database, or a nullable int in your SQL Server database, it is very convenient to map this to a nullable int in your C# business object.

int? myNum = null;

or

Nullable<Int32> myNum = null;

Being now able to represent this database value, you probably also want to be able to test for the null case and return an alternative value if it turns out to be true.  Here are four ways to do the same thing, in increasingly cool ways, because they are increasingly obscure.

With an IF ELSE block:

if (null == myNum)
    return -1;
else
    return myNum.GetValueOrDefault();

With a SWITCH block:

switch (myNum)
{
   case null:
        return -1;
   default:
        return myNum.GetValueOrDefault();
}

With a Ternary Operator:

return myNum == null ? -1 : myNum.GetValueOrDefault();

And with a Null Coalesce Operator:

return myNum ?? -1;

 

For those who think that in coding compactness == elegance, then this is the syntax for you.  For everyone else, it is a nice recipe you can use to impress co-workers at the next code review.  The most likely, and desirable, response will be:

??