Wednesday, May 07, 2008
RC4 encryption for classic ASP stops working
Microsoft dropped support for Intellisense and color-coding for classic ASP in Visual Studio 2008, but I still use it to maintain some old sites.
Well, after some minor changes to an old site, suddenly, the RC4 encryption code, by Mike Shaffer, that I was using didn't work any more. The answer really surprised me.
To make a LONG story short, I opened the site in VS08 and created a new include file for a page I was modifying. I included the file into the primary page and that caused the RC4 code to stop producing the correct output.
Visual Studio 2008 created the new include file using UTF-8 encoding. Well, for some reason that broke the RC4 encryption code. I guess it's because each character would be 2 bytes instead of 1? I thought that was just Unicode and classic ASP won't even process a Unicode file (UNICODE ASP files are not supported). I don't know.
My resolution was to make sure the classic ASP page and all its includes were saved as ANSI text. Here Notepad++ (Menu > Format > Encode in ANSI) came in very handy again.
Maybe someday I will understand The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character. Scott Hanselman also has an interesting post on the CodePage versus the CharSet in classic ASP.
Microsoft Drops Classic ASP Support in Visual Studio 2008
For better or worse, I still have to support some Classic ASP and VBScript code, well Microsoft dropped Intellisense and color-coding for classic ASP. Recommended solution: Keep my 2.5 GB install of VS05 around for those days when you need it.
I can't believe it myself. How detrimental or hard was it to maintain even just basic syntax highlighting? Even an open source product like Notepad++ offers that. Wow.
I recently found another gotcha which I will include in another post.
UDPATE [5/12/2008]: Looks like VS08 SP1 will bring back support for classic ASP. Cool!
Labels: asp, compatibility, gotchas, opinion, vs2005, vs2008
Friday, January 18, 2008
HttpFileCollection Always Zero
(Request.Files == 0) == true
I was using the AjaxFileUpload, a jQuery plug-in intended to be paired with PHP, but compatible with any server side handler. Since I use ASP.NET, I wrote an HttpHandler to receive the form post, save the file on the server, and send a JSON response.
Without investigating too closely, it looks like the AjaxFileUpload creates an iframe, moves the html file input into the iframe and submits it to specified handler. I didn't want to user "runat='server'" controls so I just put a plain html input tag in the page like so.
<input type="file" id="AjaxFileInput" />
I ran my project and everything seemed to be working and submitting, fine, but the HttpFileCollection always had a count of 0.
I created a simple page with no ajax that posted back to itself to test the plain HTML inputs, and the Request.Files collection was still empty. I tried adding the "runat='server'" attribute and it suddenly worked, of course. I didn't want to user server controls, because I wanted to add new inputs as needed with client script.
It seemed like the Request.Files collection would only be populated if I used the ASP.NET server controls, but I could not think of any reason why. Finally, I looked at the code rendered by the server controls and discovered the answer.
Every site I found said there were 2 things you needed to get the HttpFileCollection to populate.
1) Make sure the form method is "POST"
2) Make sure the form enctype is "multipart/form-data"
The AjaxFileUpload code dutifully had this right, however there is one more thing that ASP.NET needs.
3) The HTML file input must have a "name" attribute.
Here is a final sample of an accurately constructed plain HTML form that will populate the Request.Files collection.
<form action="" method="POST" name="form1" id="form1" enctype="multipart/form-data">
<input type="file" id="AjaxFileInput" name="AjaxFileInput" />
</form>
This seems like a bug, to me, and I don't know if .NET 3.0-5 fixes this. This document does not reflect what I have found to be true.
Wednesday, October 31, 2007
Print Page from IE without Prompt
<html>
<head>
<script language="javascript">
function ieExecWB(intOLEcmd, intOLEparam)
{
var WebBrowser = '<OBJECT ID="PrintBrowser" WIDTH=0 HEIGHT=0 CLASSID="CLSID:8856F961-340A-11D0-A96B-00C04FD705A2"></OBJECT>';
document.body.insertAdjacentHTML('beforeEnd', WebBrowser);
if ( ( ! intOLEparam ) || ( intOLEparam < -1 ) || ( intOLEparam > 1 ) )
{
intOLEparam = 1;
}
PrintBrowser.ExecWB(intOLEcmd, intOLEparam);
PrintBrowser.outerHTML = "";
}
</script>
</head>
<body>
<p><a href="javascript:ieExecWB(6, -1);">print</a></p>
</body>
</html>
NOTE: I don't know where I found this code so if someone needs attribution or it violates a copyright or something, let me know.
Saturday, August 11, 2007
Optional Radio Buttons
You can get around this problem by adding one option to the group and labeling it "N/A" or something. This gives the user an out. Incredibly, I have never been able to convince any of my customers to go that route. In fact, even if the radio group is required they will want the all of the options unchecked initially.
Most people get around this by writing their own logic over check boxes, but I decided to take a different approach. I finally wrote some JavaScript which will un-check a radio button if the button you click is already checked, thus allowing the user an escape route.
function RadioClick(radio)
{
var inputs = document.getElementsByTagName("input");
var checked = (radio.getAttribute("shadow") == "true");
for(var i = 0; i < inputs.length; i++)
{
if (inputs[i].getAttribute("type") == "radio" && inputs[i].name == radio.name)
{
inputs[i].setAttribute("shadow", "false");
}
}
if (checked)
{
radio.checked = false;
}
else
{
radio.setAttribute("shadow", "true");
}
}
All you have to do is add this script to your page and then just add "RadioClick" to the radio button's onClick event, like so...
<input id="ctl01" type="radio" name="GroupName" value="ctl01"
checked="checked" onclick="javascript:RadioClick(this);" />
You could easily make this script unobtrusive by adding a method that assigns onClick event by group name when the page loads.
Friday, October 13, 2006
DataFormatString Doesn't Work
[Here is the "bug" report]
You must also set the HtmlEncode attribute to false. The explanation in the bug report doesn't make sense to me though. So what if the bound value is HTML encoded. Can't the format string still be applied? I guess if the datatype is changed to string then special format strings like "{0:C}" for currency or "{0:MM/dd/YYYY}" for DateTime won't work.
Wednesday, September 06, 2006
Generic HttpContext Singleton
Joel Ross has an interesting post about implementing the singleton pattern for objects used during the lifecycle of a web request.
This got me thinking about the Generic singleton implementation that I have used before. I wondered if you could combine the two to make a Generic HttpContext singleton. Here is my first attempt. I think it should work, but I have not tried it.
I guess the key is the "key". It may be better to use the fully qualified class name for the key instead of just using the generic type's name. It may also make sense to add a "Singleton_" prefix to the name to give it a namespace within the HttpContext.
1 using System;
2 using System.Collections.Generic;
3 using System.Web;
4 using System.Runtime.Serialization;
5
6 namespace jedatu
7 {
8 public class ContextSingleton<T> where T : ISerializable, new()
9 {
10 protected ContextSingleton() { }
11
12 public static T Instance
13 {
14 get { return Factory.Current.Instance; }
15 }
16
17 private class Factory
18 {
19 static Factory() { }
20
21 internal static Factory Current = new Factory();
22
23 internal static readonly T _instance = new T();
24
25 internal T Instance
26 {
27 get
28 {
29 if (HttpContext.Current == null) { return null; }
30 if (HttpContext.Current.Items[_instance.GetType().Name] == null)
31 {
32 HttpContext.Current.Items[_instance.GetType().Name] = _instance;
33 }
34 return (T)HttpContext.Current.Items[_instance.GetType().Name];
35 }
36 }
37 }
38 }
39 }
Wednesday, August 02, 2006
PowerShell Baby Step: Change File Attributes
I do know that I hate the limitations of batch files and have thought about using Ruby and now PowerShell instead. I installed ShinyPower to help me navigate the PowerShell help. I read some tutorials. Gradually, I was getting ready to do something.
Well, today I finally wrote my first PowerShell code and this is why.
I use a fantastic program called TimeSnapper. It saves an image of my screen at a pre-determined interval--in my case every 5 minutes. This helps me keep track of what I have been working on. Well, I copied the image files to a new location and the CreateDate changed. This meant that TimeSnapper thought all the images were captured at the same time each day. Ugh. Then I thought, "this sounds like a job for PowerShell"
After a little exploration I came up with a script to fix the problem with the files.
ls | foreach { $_.CreationTime = $_.LastWriteTime }
Breakdown:
Step1 [ ls ] Call the ls alias to list the files in a given directory.
Step2 [ | ] Pipe the resulting list of FileObjectInfo objects to a for each statement
Step3 [ foreach { ] Begin the for each
Step4 [ $_ ] Reference the current object in the collection
Step5 [ .CreationTime = $_.LastWriteTime ] Set the CreationTime equal to the LastWriteTime
Step6 [ } ] End the for each
In the end, it's a pretty simple one-line script, but it helped me make some progress understanding the PowerShell syntax.
Here's some other cool PowerShell tricks. "Can your programming language do this?"