navigation
 Sunday, August 12, 2007

I was configuring Custom Errors in the web.config of my ASP.Net 2.0 application, and set it up as follows:

<customErrors mode="remoteOnly" defaultRedirect="~/Error.aspx">
  <error statusCode="403" redirect="~/AccessDenied.aspx" />
  <error statusCode="404" redirect="~/Error404.aspx" />
</customErrors>

I had found the syntax on MSDN. To my surprise, the applicationm wouldn't start, it told me there was something wrong with the value of the mode attribute.

So I went back to MSDN and noticed I had looked at the .NET Framework 1.1 documentation. Clicking on the corresponding 2.0 documentation, I found it had changed to initial Caps:

<customErrors mode="RemoteOnly" defaultRedirect="~/Error.aspx">

Duh! I guess my chances of getting this right the first time were remote only...

posted on August 12, 2007  #    by John Waters  Comments [0] Trackback
 Thursday, August 09, 2007

I've been looking at the "Scheduler" entry on the DNN Host menu for quite a while now, thinking about looking into it further and wondering how I might be able to take advantage of the promise that's there.

First, the bad news: the scheduler only checks if there's a scheduled activity that needs to be run when the DNN server gets hit. So, for instance, if you have a task that you want to run every ten minutes, and nobody hits your website for three hours in the middle of the night, the task will not run until the next time there's a web request to your site. There are some DNN ways to work around this - go to http://www.dotnetnuke.com/, and search for KeepAlive, which is a module that will automatically access your website just prior to Application_End.

Now the good news: writing a scheduled service is as easy as can be, once you know the tricks. Here's the code for a complete Hello World implementation, which you should add as a new class to your App_Code folder for the project you're working on.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using DotNetNuke.Services.Scheduling;

namespace Falafel.WebPlanner
{
public class TestClass1 : SchedulerClient
{
public TestClass1(ScheduleHistoryItem objScheduleHistoryItem) : base()
{
this.ScheduleHistoryItem = objScheduleHistoryItem;
}

public override void DoWork()
{
try
{
this.ScheduleHistoryItem.Succeeded = true;
this.ScheduleHistoryItem.AddLogNote("Notification processing completed at " +
                  DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString());
}
catch (Exception exc)
{
this.ScheduleHistoryItem.Succeeded = false;
this.ScheduleHistoryItem.AddLogNote("Scheduled service failed");
this.Errored(ref exc);
}
}
}
}

Let's look at a couple of the things that are going on here. First, notice that the constructor includes a reference to a "ScheduleHistoryItem. This is used by the DNN system to pass success/failure information, as well as any messages that need to be logged. The other feature is the DoWork() method. This is the method that takes care of business for you, the method that is called every time the scheduler fires the event. Using the DoWork method as a springboard, you can accomplish anything you like programmatically.

After compiling this code into your application, the last thing you need to do is to schedule the event. Start your site from within the IDE, and log in as host. Go to the Host -> Schedule menu entry, and select "Add Item To Schedule".  The entry in the first text box is a little odd, asking you for the full class name and assembly. In the case of the example above, I enter Falafel.WebPlanner.TestClass1, App_SubCode_Falafel_WebPlanner. Set the period for the schedule to call for the time period you'd like (for the purposes of this demonstration, I chose every 15 seconds), and also (for demo purposes) select to retain schedule history for 10 iterations. Click the "Schedule Enabled" checkbox, and update.

Just to prove the point, if there's no activity on your system (and there probably should not be - you're doing this on a development system, aren't you?), leave the site alone for a minute or two. After waiting for this respectful length of time, go back to the main Host -> Schedule page, locate your entry, and click on history. You shouldn't see any more than one entry. If you click around on your website for a while, then inspect the history again, yo'll see that the scheduled events have fired on a (fairly) regular basis. Leave the site alone again for a while, and you'll notice that the events also have not fired.

In summary, the DNN scheduler is a pretty simple yet very useful tool to run scheduled tasks if either a) your site is an active one, or b) you use some method of keeping your site alive.

posted on August 9, 2007  #    by Rick Miller  Comments [1] Trackback
 Friday, August 03, 2007

I spent some time banging my head trying to get Selenium to select an item from a Telerik RadCombobox for ASP.NET. It turns out I was very close but missing one small detail and that was to call mouseOver on the item I was trying to select before calling Click. I evetnually found the answer on the Teleik forums here. Falafel Software is a big fan of Telerik and it's nice to know their using Selenium to test their controls.

posted on August 3, 2007  #    by Steve Trefethen  Comments [0] Trackback
 Tuesday, July 31, 2007

The other day I was trying to figure out why the ItemCommand associated with an ImageButton in a DataGrid had stopped firing and was surprised by why...

Here is the grid in action:

When I clicked on any of the ImageButtons in the grid, the page did post back, but the ItemCommand didn't fire. I experimented with binding the grid at different points in the page lifecycle, but that didn't help. I also tried switching from a DataGrid to a GridView, thinking such a drastic change might get rid of whatever oddity was going on. No such luck.

Finally, I noticed that the grid attribute EnableViewState was false. Originally, this grid had contained some template items with editable content, including text boxes, drop down lists and checkboxes, and ViewState was turned on. But I replaced that functionality with some client side logic using JavaScript and JSON web service calls, so I figured no viewstate was needed any more, and had turned it off. It wasn't until a few weeks later when someone clicked on these image buttons that the problem showed up.

So, long story short, I changed EnableViewState to true, and voila, it started to work again. It beats me why viewstate is needed for a command event to fire when an image is clicked (I could see the image.x and image.y variables in the postback even when it was turned off), somehow the event bubbling from the image click to the containing DataGrid's ItemCommand handler (RowCommand in the GridView) is dependant on viewstate being turned on. If anyone knows why I am all ears!

posted on July 31, 2007  #    by John Waters  Comments [0] Trackback
 Monday, July 30, 2007
 | 
posted on July 30, 2007  #    by Adam Anderson  Comments [0] Trackback
 Sunday, July 29, 2007

Back at TechEd 2007 in Orlando, Florida, both teams celebrated the release of the Telerik radControls Training courseware authored by Falafel Software and the start of a great relationship.  Here at Falafel we have nothing but respect and admiration for Telerik's products and their quality.  At the same time, we all here enjoy the Bulgarian spirit, sense of humor and great team.

The picture below was taken at the Texas De Brazil steakhouse with both teams after 14 bottles of Wine, and a lot of other weird drinks, for some reason no one remembers this picture on both teams Beer

posted on July 29, 2007  #    by Lino Tadros  Comments [0] Trackback
 Tuesday, July 24, 2007

While having some fun with the Visual Studio SDK I ran across a great example of a Navigation window by Gaston Milano.  It's a great sample to start with if you would like to dive into Visual Studio Package development.  One item of note that I found while using the navigation window on a very large project is that Visual Studio 2005 kept crashing everytime the window would be brought up.  I noticed that before VS crashed it had a difficult time drawing things. I immediately thought of a GDI leak.  I opened up Task Manager and checked the GDI objects and sure enough every time I openned the window the GDI object count would skyrocket upwards, never to return to a sane GDI count again.  VS crashed after reaching a count of about 10,000 GDI objects and I don't blame it for doing that either :) 

The offending routine, the getter for the HierarchyItem::Icon property in HierarchyItem.cs, calls a method NativeMethods.ImageList_GetIcon() which merely vectors off into the win32 version of ImageList_GetIcon().  Looking at the MSDN documentation for this routine you'll notice that the remarks at the end state

"It is the responsibility of the calling application to destroy the icon returned from this function using the DestroyIcon function"

Looking at the code you'll notice that DestroyIcon is never called on the temporary HICON returned from this call so every time this routine is called I noted 2 HICONs being leaked.  And on my large project, this really started adding up.

The fix?

Change the following code in HierarchyItem.cs:

      int handleIcon = NativeMethods.ImageList_GetIcon((int)imageList, (int)index, hbmMask);
      try {
          this.icon = (Icon)Icon.FromHandle((IntPtr)handleIcon).Clone();
      }
      catch (ArgumentException) {
      }
To:
int handleIcon = NativeMethods.ImageList_GetIcon((int)imageList, (int)index, hbmMask);
try {
     this.icon = (Icon)Icon.FromHandle((IntPtr)handleIcon).Clone();
     NativeMethods.DestroyIcon(handleIcon); // <== added to destroy the temp HICON
    } catch (ArgumentException) {
    }

And add a reference to DestroyIcon in the NativeMethods class like so:

        [DllImport("USER32")]
        public static extern int DestroyIcon(int HICON);
Hope that helps any of you running into similar problems.
posted on July 24, 2007  #    by Adam Markowitz  Comments [0] Trackback

So you have a cool asp.net application and everything is running great. You're running it under NET 2.0 and you're using a report server on the same machine. It may run great for months, and then out of nowhere your web application starts displaying the “Service unavailable” page. It does this until you do an iisreset. Where did this message come from? I recently had to find out for myself. My search lead me to the Event Viewer on the server and five warnings about various system failures that read something like this:

A process serving application pool 'ASP.NET V2.0' suffered a fatal communication error with the World Wide Web Publishing Service.

After the fifth warning I would get the following error:

Application pool 'ASP.NET V2.0' is being automatically disabled due to a series of failures in the process(es) serving that application pool.

After the iisreset, things would go OK, but eventually the above warning/error pattern would repeat. What was going on? Why five warnings, the single error, and then the “Service unavailable” page? Well, when you search for "Application pool 'ASP.NET V2.0' is being automatically disabled due to a series of failures", you get plenty of hits. There are plenty of ways to get these errors. What I ended up finding out was that my report server and my web application were using the same application pool. I would not think this would be a big deal, until I found this tab in the properties of the application pool within the IIS Manager.

Mystery solved. It was doing exactly what it was supposed to do. The Enable rapid-fail protection was enabled and I had gotten five failures within 5 minutes to cause the application pool to be disabled. Let's say your web application calls for a report from your reports server. If your reports server fails for some reason, you can also get a failure with your web application. Since they are both in the same application pool this is two strikes with one failure. A couple more of these and your application pool gets shut down. Lesson Learned. It's good practice to move the web application and reports servers into their own application pools.

posted on July 24, 2007  #    by Bary Nusz  Comments [0] Trackback
 Monday, July 23, 2007

I am working on a web application, and some of the client side logic uses JavaScript to get an integer value from a text box. A user logged a bug claiming that when he entered a value that had a leading 0, for instance 0556, the result was in his words "a random number".

I looked up the parseInt global function here, and lo and behold! parseInt interprets a leading 0 as denoting that an octal number follows! It also has special processing for 0x (hexadecimal). To prevent this interpretation, you can specify the radix yourself in an overload of parseInt, for instance:

parseInt( tb.value, 10 );

For base (radix) 10. 

That's all I have to say about that!

posted on July 23, 2007  #    by John Waters  Comments [0] Trackback