Monday, October 1, 2007

The mysterious problem with WebResource.axd

Ever since I've started using embedded resources I've been running into this problem:

The WebResource.axd handler must be registered in the
configuration to process this request.
It occurs when an application is updated with an assembly that uses embedded resources.

It's a rather nasty problem because it will persist until the worker process is fully restarted. This is because the exception is triggered by a static field that is evaluated only once (!). Fredrik Haglund describes the mechanism here. Fredrik also offers a workaround, but it's a dirty one using reflection to tweak private variables. This work around will probably only work in full trust sites and may break with future updates of .NET. It does however get the job done for now.

Here's the code (slightly modified from Fredrik's version):
public static void WebResourceHandlerFix()
{
Type type = typeof( System.Web.Handlers.AssemblyResourceLoader );

System.Reflection.FieldInfo handlerExistsField =
type.GetField( "_handlerExists",
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Static );

System.Reflection.FieldInfo handlerExistsCheckedField =
type.GetField( "_handlerExistenceChecked",
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Static );

if ( null != handlerExistsCheckedField &&
null != handlerExistsField )
{
if ( ( bool )handlerExistsCheckedField.GetValue( null ) &&
    !( bool )handlerExistsField.GetValue( null ) )
   handlerExistsCheckedField.SetValue( null, false );
}
}
}

Note: This problem can also occur when trying to map URL's to a handler through a section in web.config. For example, this may cause problems:

<location path="virtualpage.aspx">
<system.web>
 <httphandlers>
    <add path="*" verb="*" type="Example.Web.Customhandler" />
 </httphandlers>
</system.web>
</location>

Because it will override the handler for WebResource.axd. Instead, try to add the mapping for the virtual page to the main <httphandlers> section in web.config.

4 comments:

Anonymous said...

I've inherited some code that has this problem caused by the note at the bottom of your blog. Basically the guy wrote a handler that handles every (*) path. The thing is, I'm not quite sure I understand what you are saying the solution is.

He has his handler looking for trace.axd so that it can create the expected handler and use that in that instance, but if I try to do the same thing for WebResource.axd I get the error mentioned above before the code ever even gets to my handler.

Would you mind posting a possible solution for the note at the bottom?

Marnix said...

The point of the note is that you should not override WebResource.axd. ASP.NET needs this URL to map to it's internal handler and it will check your configuration to see if this is the case. If you map webresource.axd to your custom handler instead, ASP.NET will detect this and throw the exception.
By registering your handler after the webresource.axd handler you could get the effect of mapping all urls except webresource.axd to a custom handler.
I hope this helps...

Anonymous said...

Thanks for the solution. I was running into some additional problems after your proposed change, but once I resolved all of those it now seems to be working fine.

Anonymous said...

Thank you. Your hint (worker process) probably saved me a lot of time.