Chris Haas's Blog

April 22, 2009

True ASP.Net (and IIS) 404 errors

Filed under: Uncategorized — Tags: , — chrishaas @ 9:26 pm

UPDATE: I should found out that in ASP.Net 3.5 the <customErrors> section in web.config now supports the attribute redirectMode which default to ResponseRedirect but can be changed to ResponseRewrite. This will force the proper HTTP status codes to come through for errors.

So I launched a new site porting it from static .html files to dynamic .aspx. I then created an entry for 404’s in web.config and also told IIS to send 404’s to the same page for everything that ASP.Net didn’t handle (images, html files, etc). So simple, right? Unfortunately both ASP.Net and IIS don’t appear to actually send a 404 status code for 404’s if you have a 404 handler specified. IIS actually sends a 200 OK and performs the equivalent of a Server.Transfer. ASP.Net actually sends a 302 Found which is a client-side redirect.

Now, you may not care about this, but if you’re trying to purge search engines of old content you should.

The fix, at first glance, is simple. In Page_Load on the 404 handler page just send the proper status code using Response.StatusCode = 404. This actually fixes the problem with IIS but we’ve still got an ASP.Net problem. ASP.Net will actually still send the 302 redirecting people to the 404 page and then send the 404 code. So if page Blah.aspx doesn’t exist you’ll get a 302 code saying to go to PageNotFound.aspx. When the browser requests PageNotFound.aspx they finally get the 404 response. Now maybe that’s good enough for you, but not for me. When I 404, I want to know right away, not after a redirect.

I found the solution here and have reproduced the code below for easy copy-and-paste. They don’t explicitly mention it in the article but you MUST set the <customErrors> to Off or at least RemoteOnly. I know that sounds weird but the code below still actually processes the <customErrors>, it just does it instead of letting ASP.Net handle it for you.

The article talks about creating a DLL but you can just as easily drop it into App_Code as a file named HttpErrorModule. Then just add <add name="HttpErrorModule" type="HttpErrorModule" /> to your <httpModules>.

One other thing to note, this module actually overrides all errors and sends their proper codes in the response stream. This shouldn’t cause any problems but you should be aware of it when debugging. You could very easily add some logic to check for 404’s only, too.

'Code from: http://www.colincochrane.com/post/2008/01/ASP-NET-Custom-Errors-Preventing-302-Redirects-To-Custom-Error-Pages.aspx
Option Strict On
Option Explicit On

Imports System.Web
Imports System.Web.Configuration

Public Class HttpErrorModule
    Implements IHttpModule

    Public Sub Dispose() Implements System.Web.IHttpModule.Dispose
        'Nothing to dispose.
    End Sub
    Public Sub Init(ByVal context As System.Web.HttpApplication) Implements System.Web.IHttpModule.Init
        AddHandler context.Error, New EventHandler(AddressOf Context_Error)
    End Sub

    Private Sub Context_Error(ByVal sender As Object, ByVal e As EventArgs)
        Dim context As HttpContext = CType(sender, HttpApplication).Context
        If (context.Error.GetType Is GetType(HttpException)) Then
            ' Get the Web application configuration.
            Dim configuration As System.Configuration.Configuration = WebConfigurationManager.OpenWebConfiguration("~/web.config")

            ' Get the section.
            Dim customErrorsSection As CustomErrorsSection = CType(configuration.GetSection("system.web/customErrors"), CustomErrorsSection)

            ' Get the collection
            Dim customErrorsCollection As CustomErrorCollection = customErrorsSection.Errors
            Dim statusCode As Integer = CType(context.Error, HttpException).GetHttpCode

            'Clears existing response headers and sets the desired ones.
            context.Response.ClearHeaders()
            context.Response.StatusCode = statusCode
            If (customErrorsCollection.Item(statusCode.ToString) IsNot Nothing) Then
                context.Server.Transfer(customErrorsCollection.Get(statusCode.ToString).Redirect)
            Else
                context.Response.Flush()
            End If
        End If
    End Sub
End Class

Want Arial Narrow Bold or Italic?

Filed under: Uncategorized — Tags: , — chrishaas @ 9:25 pm

Office 2007 shipped several weights of Arial Narrow but apparently Microsoft made a mistake in the font meta information that causes Adobe products to only recognize Arial Narrow Regular. You can find more information here and also find the relatively painless method of obtaining the hotfix or you can use your crazy-mad ninja skills and search for it. And just in case you’re super lazy:

http://thehotfixshare.net/board/index.php?autocom=downloads&showfile=9298 (not linked on purpose)

Oh, and by the way, after you install the hotfix, quit all Adobe programs, drop to a command-line, cd to root and run the following command to purge the Adobe font cache:

del adobefnt*.lst /S /F

April 14, 2009

Map file extension to ASP.Net

Filed under: Uncategorized — Tags: , — chrishaas @ 9:24 pm

I’m converting a site from static HTML to dynamic ASP.Net but I don’t want to rename every page or worry about dropping in pages in the search engines. So I decided to just map HTML files to the ASP.Net processor. I could have sworn that I had done this before and all I had to do was make the normal IIS setting change (http://msdn.microsoft.com/en-us/library/bb515343.aspx). But that just returned a blank page. The fix is to add a buildProvider and an httpHandler.

<configuration>
    <system.web>
        <compilation debug="false">
            <buildProviders>
                <add extension=".html" type="System.Web.Compilation.PageBuildProvider"/>
            </buildProviders>
        </compilation>
        <httpHandlers>
            <add verb="*" path="*.html" validate="false" type="System.Web.UI.PageHandlerFactory" />
        </httpHandlers>
    </system.web>
</configuration>

clr20r3 error

Filed under: Uncategorized — Tags: — chrishaas @ 9:23 pm

Ran into this error recently on the system that I moved. My problem was that the program was running under a different user account which didn’t have the needed Adobe InDesign PDF export presets loaded. When my app tried to export a PDF (with no error handling) the system threw an UnhandledException and crashed to desktop with nothing but crap in the event log. To help diagnose the problem I added an UnhandledException handler (sounds weird, I know) that gave me a nice stack trace. I ran it with the debug version so I got line numbers, too. You can add an UnhandledException handler like so:

    Sub UnhandledException(ByVal sender As Object, ByVal e As UnhandledExceptionEventArgs)
        If e.IsTerminating Then
            Dim o As Object = e.ExceptionObject
            MessageBox.Show(o.ToString)
        End If
    End Sub
    Public Sub New()
        AddHandler AppDomain.CurrentDomain.UnhandledException, AddressOf UnhandledException
    End Sub

April 10, 2009

How to add metadata to Facebook link

Filed under: Uncategorized — Tags: , — chrishaas @ 9:22 pm

When you post a link in Facebook, Facebook scans the page that you’re posting and looks for certain tags to tell it what the links is about. Unless you’ve setup your site with special markup, however, Facebook will just grab the page’s title and the first paragraph or two of the pages content, and possibly a random image. If you want to control this you need to add special markup.

Below is a sample of how to post a video:

<meta name="title" content="Neil Michelin's Huge Muskie" />
<meta name="description" content="Neil talks about catching his personal best, a fish nearing the 60&quot; mark, while Muskie fishing August second, 2008 on Lac Seul tossing a Shumway Flasher." />
<link rel="image_src" href="http://video.outdoorsfirst.com/159c6604-219b-441a-be7c-c86f56a4fe2c.wmv.jpg" />
<link rel="video_src" href="http://upload.outdoorsfirst.com/flash/video2.2_med.swf?ad=http://video.outdoorsfirst.com/slug_toyota.flv&amp;atitle=Advertisement&amp;video=http://video.outdoorsfirst.com/159c6604-219b-441a-be7c-c86f56a4fe2c.wmv.flv&amp;btitle=Neil Michelin's Huge Muskie&amp;ref=fb"/>
<meta name="video_height" content="387" />
<meta name="video_width" content="486" />
<meta name="video_type" content="application/x-shockwave-flash" />

April 8, 2009

Mass find and replace

Filed under: Uncategorized — chrishaas @ 9:21 pm

So, you need to do a massive find and replace but don’t have VS or Dreamweaver installed? Here’s a sweet little freeware app to do that:

http://www.snapfiles.com/get/bkreplace.html

(I think there’s a newer version under a different name, too)

SQL Server 2000 w/o the GUI

Filed under: Uncategorized — Tags: — chrishaas @ 9:21 pm

Okay, not totally, but this process starts without the GUI. I had two SQL servers, one without the GUI tools installed. In a domain environment this is fine because you can just snap to the machine using your domain credentials. If you don’t have a domain and forgot to create a local account (or can’t remember the sa password) before disconnecting from the domain, however, you’re in for a little trouble. Okay, its not that bad really. SQL Server 2000 installs a command line tool that you can use to create a new user and elevate that user as needed. In my case, I wanted to manage both SQL Servers from the one SQL Server with the GUI tools installed. Luckily I have mixed-mode authentication installed so I didn’t need to try to get the sa password.

  1. Drop to a command line and navigate to C:\Program Files\Microsoft SQL Server\80\Tools\Binn (or wherever your tools are installed to, obviously).
  2. Type (case-sensitive):
    osql -E
    This will log you in using your current logged in credentials
  3. Type (two lines):
    EXEC sp_addlogin 'Username', 'Password'
    GO
    Replacing Username and Password as needed
  4. In my case, I just wanted the account to have total control since I was going to be managing this remotely so I ran (two lines):
    EXEC sp_addsrvrolemember 'Username', 'sysadmin'
    GO
    Replacing Username as needed
  5. Alternatively you can run this if you want to use a custom role (two lines):
    EXEC sp_addrolemember 'role name', 'Username'
    GO
    For some reason the two role sproc’s parameters are in different orders

With this you should be able to login remotely.

XDocument, FileStream and UNC Paths

Filed under: Uncategorized — Tags: — chrishaas @ 9:20 pm

We moved two servers yesterday that were originally part of a Windows domain. At the new place the domain would no longer exist (we also transffered ownership) so we removed the machines from the domain and set them to be part of a standard workgroup. For the most part this worked accept there was one application that was pulling XML files from one machine to another using UNC paths and standard FileStreams. ASP.Net was throwing an IOException of Logon failure: unknown user name or bad password. Makes sense, the FileStream call wasn’t doing any type of authentication and to the best of my knowledge, there’s no way to specify any credentials (short of using unmanaged code). I started to think of ways around this. In the past I had played with AppDomains which allowed me to reset the credentials but I remember that opened up a whole other can of worms. Then I realized that I was just using the FileStream to give me a String that I was passing to XDocument.Parse(). Well, XDocument also has a Load() method which takes a URL. So, a quick easy solution was to map the UNC path in IIS as a virtual folder, specify the credentials for the remote machine and then use the XDocument.Load() method to load the data. If the document wasn’t an XML document I could have used the same process except use the WebClient instead (Dim S = New System.Net.WebClient().DownloadString("http://..."))

April 6, 2009

Hyperlinks not working in IE6

Filed under: Uncategorized — Tags: , — chrishaas @ 9:17 pm

If you’re using Internet Explorer 6’s proprietary filter CSS property to apply a transparent background image to an element that contains links you may find that the links don’t work anymore. I stumbled around on the net looking for an answer but everyone was talking about problems stemmed from absolute positioning of items. Even though I had nothing positioned absolute I tried those fixes anyway but they of course didn’t work. Finally I stumbled upon this link which points out that the fix is to not change the container’s position but instead the position of the links within the container. It also helped to remind me that all elements default to a position of static, not relative or absolute.

#topnav{background-image:none;filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=/images/top_nav_bg.png);}
#topnav a{position:relative;}

Blog at WordPress.com.