Skip to the content Back to Top

 

On a search form with only one search term box and one submit button, such as the Quick Search form in the Andornot Starter Kit, the usual user behaviour is to type search terms and press the Enter key. However, there is a longstanding issue with ASP .NET that results in seemingly nothing happening in this case, in some browsers. The form does a weird empty postback because it submits the form, but does not call your ASP.NET submit button's click event: i.e., it does a postback, but does not do anything. The user must instead use the mouse to click the Submit button.

A simple workaround for this is to add a second search box to the form, but make it invisible. For example, add:

<input type="text" style="display:none;" />

Now when the user presses the enter key, the subsequent postback operates as expected (i.e. in the case of the Andornot Starter Kit Quick Search form, it submits the search instead of just doing an "empty" postback that doesn't do anything).

More information on this ASP.NET behaviour is available here. Information on similar behaviour in AJAX Update Panels is in an earlier Andornot developer blog post.

In IIS 6.0, different versions of the .NET framework can co-exist on the same website but must use separate application pools. Once a .NET process "grabs" the app pool, other .NET processes are denied its use and report generic server errors in the browser. Which .NET process gets an app pool first depends on which is first requested after an application pool recycle. For example the .NET 2.0 process might get the application pool first, and all .NET 1.1 applications that rely on the application pool fail to run; end users see generic server errors that do not report what is really going on.

Installing Inmagic Webpublisher or Genie

Although Webpublisher inmagicbrowse and Genie inmagicgenie virtual directories are correctly set to use .NET 2.0, the installer lets the parent website determine which application pool to use. A typical Windows 2003 Server might have .NET 1.1 and DefaultAppPool as the default on new websites. If there are any .NET 1.1 applications already on the server that rely on DefaultAppPool, then inmagicbrowse and inmagicgenie are setting the server up for an application pool conflict.

Separate Application Pools

Set up a separate application pool just for Genie, and one for Webpublisher. This way you avoid any conflict with applications currently on the server, but also allow for changes in .NET dependency in future: when Genie starts using .NET 3.5 you won't have to worry about re-organizing application pools. It's also good practice to isolate applications like this so that when one does go down, it doesn't take other applications with it.

Inmagic Webpublisher canned query URLs can be very very long, so I wrote a .NET HttpHandler that shortens them and bolsters their persistence into the bargain.

Here's an example of a very long Webpublisher query string that displays a single record from the sample cars database.

http://localhost/dbtw-wpd/exec/dbtwpub.dll?AC=GET_RECORD&XC=/dbtw-wpd/exec/dbtwpub.dll&BU=&TN=cars&SN=AUTO29781&SE=267&RN=0&MR=0&TR=0&TX=1000&ES=0&CS=1&XP=&RF=&EF=&DF=&RL=0&EL=0&DL=0&NP=1&ID=&MF=&MQ=&TI=0&DT=&ST=0&IR=1&NR=0&NB=0&SV=0&SS=0&BG=&FG=&QS=&OEX=ISO-8859-1&OEH=ISO-8859-1
 

See? Looooooooong. Not at all memorable, and difficult to display or pass around. But with the handler in play, I can now shorten it:

Both get the same result:

Porsche

Porsche

A classic best-seller, the Porsche 911's anodized aluminum tub chassis has a strong front brace for extra support. A steel mount holds the engine snugly in place. Mounted on 25-degree caster blocks, the A-arms are longer than most and can be adjusted for low-speed steering or short tracks. The upper links have coated turnbuckles which can also be adjusted for different terrains. The rear suspension uses extra-long arms and variable shocks. The engine is side mounted and sits lower than many models. The clutch, which happens to double as the brake drum, is mounted on the crankshaft.

Configuration

In the case of the short URL, the original query remains valid, but is held in the application's web.config:

<PermanentUrlSettings>
    <queries>
        <add name="mycarquery" uniqueIDField="Product-Number" queryParameters="/dbtw-wpd/exec/dbtwpub.dll?AC=qbe_query&amp;TN=cars" />
    </queries>
</PermanentUrlSettings>

The original query is called upon with an alias: qn=mycarquery. The id parameter is appended to focus the query to a single record, or, if no id parameter, the base query is run as-is.

The short URL path is /shorturl.ashx, but this is completely imaginary. And configurable in web.config:

<httpHandlers>
    <add verb="GET" path="shorturl.ashx" type="Andornot.Web.PermanentUrlHandler"/>
    <add verb="GET" path="/shorturl" type="Andornot.Web.PermanentUrlHandler"/>
    <add verb="GET" path="whatever/" type="Andornot.Web.PermanentUrlHandler"/>
</httpHandlers>

Using the examples above, any one of the following would be valid.

http://localhost/shorturl.ashx?qn=mycarquery

http://localhost/shorturl?qn=mycarquery

http://localhost/whatever/?qn=mycarquery

None of the paths exist on disk, which is what an HttpHandler is all about. The handler hijacks the request to any path bound to it, whether the path exists on disk or not.

Advantages

Mapping entire queries to simple aliases has some immediate and obvious advantages:

  • Short URLs.
  • URLs are friendlier, more memorable, and hackable. (If you are trying to make your information available this is a *good* thing.)
  • You can map almost any URL path you want to the handler, in order to organize query paths into pleasing hierarchies of your own devising:
    • e.g. /catalog/queries?qn=mycatalogquery
    • /archives/photos?qn=myphotoquery
    • etc.
  • You can define and update queries in one central location.
  • URLs become more persistent. Modifications to queries will not break URLs already in the wild:
    • Switch from Dbtext to Content Server without breaking any canned queries
    • Switch display forms or any parameter
    • Switch hostname, even

There's been a lot of excitement about a new language feature in the .NET Framework 3.5 "Orcas": extension methods.

Extension methods allow developers to add new methods to the public contract of an existing CLR type, without having to sub-class it or recompile the original type. -- ScottGu's Blog

That's High Geek for "you can tack on methods to existing .NET classes." For example, you could extend the String class with a UrlEncode method:

C# Extension Method: UrlEncode

public static string UrlEncode(this string s)
{
    return HttpUtility.UrlEncode(s);
}

Then you could call it from any string:

string str = "blah";
string strEncoded = str.UrlEncode();

That's all very useful, and I'll make heavy use of it, I'm sure. It's not exactly new, though. Javascript has had extension methods on offer for years with the prototype object. Entire javascript frameworks have been built around it: Prototype, mootools, jQuery, etc. Taking the above UrlEncode example:

Javascript Extension Method: UrlEncode

String.prototype.UrlEncode = function()
{
    return encodeURIComponent(this);
}

So, as far as the coming extension methods in .NET go, I guess I'm less "wow, neato" and more "it's about time." I'm *such* a jerk.

Many of the ASP.NET web applications we build use SMTP to send email for one reason or another. Order confirmations, mostly, or selected search results.

Testing code that sends email has always been a pain. We have servers with SMTP service that I could point at from my development workstation, but their various restrictions have been, well, restricting. Nor did I ever like the idea of letting SMTP run openly on my local machine in XP. Not that I had much choice, because a) I had to ensure that the code I wrote followed through with the email send, and b) I wanted to view the email as email to ensure it looked the way it ought.

So along comes Vista with IIS 7. And SMTP is not included. It is included with Longhorn Server 2008 with IIS 7 (apparently), but not Vista. I now no longer have the choice of running SMTP locally. Disaster!

Well, as it happens, I'm fine. I'm better than fine, because I stumbled across a better solution all around. I use a pickup directory location.

Using a pickup directory location lets me specify a folder on my local machine for the email generated by System.Net.Mail. It's not sent anywhere, it's just dumped in that location as a *.eml file which can be viewed by Vista's built-in Windows Mail.

The best thing is, I don't have to change my code in any way to make this happen. I only need to add a snippet to the web.config as follows, identifying the (absolute) directory for pickup:

<system.net>
  <mailSettings>
    <smtp deliveryMethod="SpecifiedPickupDirectory">
      <specifiedPickupDirectory 
pickupDirectoryLocation="v:\inetpub\mailroot\pickup"/>
    </smtp>
  </mailSettings>
</system.net>

I did have to make sure that the ASP.NET worker account, NETWORK SERVICE, had read/write access to that location.
And here's the result. One double-click and I get to see it as it would appear in my inbox:
CropperCapture[17]
Probably other developers are like, well *duh*, but this was a new and very pleasant discovery for me.

Categories

Let Us Help You!

We're Librarians - We Love to Help People