Why my HttpHandler is ignored? - asp.net

In an ASP.NET application, I need to do some changes on every CSS file sent.
So I created an HttpHandler (inside the app itself), added:
<add verb="*" path="*.css" type="MyWebsite.CssTestHandler,MyWebsite"/>
to Web.config in system.web/httpHandlers and modified the handler like this:
public void ProcessRequest(HttpContext context)
{
context.Response.Clear();
context.Response.Write("Hello World");
context.Response.End();
}
But CSS files are still just like they were before, so the handler is just ignored.
What I'm doing wrong?

You need to setup a wildcard map in IIS, see the following link:
http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/5c5ae5e0-f4f9-44b0-a743-f4c3a5ff68ec.mspx?mfr=true
This will cause the request for the CSS file to be served by ASP.NET rather than just IIS.
If the application serves very high traffic, consider setting this mapping for .css files only, or even better change the CSS data in the page rather than changing the file.

Check this page for instructions on all 3 cases of IIS version (6, 7 Classic pipeline and 7 Integrated pipeline):
http://learn.iis.net/page.aspx/508/wildcard-script-mapping-and-iis-7-integrated-pipeline/
According to it, in case of Integrated pipeline, you need to add the following config parameter:
runAllManagedModulesForAllRequests="True"

The App ignores your CSS files because IIS ignores CSS files.
It's not mapped to an executable in IIS.
alt text http://www.fastpics.net/sharepics/imih41904722.jpg
Try adding the .css extension and map it to the .NET dll.

Related

How to check whether Application_BeginRequest is called for static resources like images on real IIS webserver?

We have an ASP.NET 4.0 website, and we use the Application_BeginRequest event in Global.asax to do some smart redirects. When debugging the solution under the local ASP.NET Development Server provided by Visual Studio (no IIS), Application_BeginRequest is called for both apsx pages and the static resources like css files, jpg/gif images, etc our pages contain.
That's a known issue, but what about the real IIS hosting of our hosting provider (Windows 2008/IIS 7.0)? How can we check whether this happens for the static resources? And how to prohibit this?
All requests will flow through Application_BeginRequest unless you tell the webserver to behave differently by setting runAllManagedModulesForAllRequests to false
<system.webServer>
<modules runAllManagedModulesForAllRequests="false" />
</system.webServer>
If you don't have access to web.config then you can set up a quick test : publish two distincts images : redirect.jpg and noredirect.jpg and set a redirection in Application_BeginRequest and see if it occurs or not
var url = ((System.Web.HttpApplication)sender).Request.Url;
if (url.EndsWith("noredirect.jpg"))
{
Response.Redirect(url.replace("noredirect.jpg","redirect.jpg"));
}
Then try to access "noredirect.jpg", if "redirect.jpg" shows instead then the redirect is in action ( = default setting)
You can try;
if (Request.Path.ToLowerInvariant().IndexOf(".aspx") > -1)
{
// static files
}

ASP.Net IgnoreRoutes Does not work

I have an svg file as my assets and in routeconfig, I have mentioned the below code
routes.IgnoreRoute("{*svg}", new { svg = #"(.*/)?.svg(/.*)?" });
This seem to be working fine with cassini (Visual Studio 2012 Buit-in Deployment Server) but when I deploy it to Azure I get a 404.
Is my IgnoreRoute statement right ? or any other solutions ? all other images, style sheets seems to work ok.
Thanks a lot in advance.
You never have to ignore routes for files that physically exist on disk, the routing module will not try to route those requests. You only need to ignore routes to other virtual resources.
Azure web sites do not have a mime type configured for .svg files, at least at the end of last year they didn't. You can configure a mime type for svg in the <system.webserver> section of your web.config file:
<staticContent>
<remove fileExtension=".svg"/>
<mimeMap fileExtension=".svg" mimeType="image/svg+xml"/>
</staticContent>
The remove is there to prevent errors on servers that already have an entry for .svg. It's an error to add a duplicate fileExtension, but not an error to remove a non-existent extension.
More here: Configuration Tips For ASP.NET MVC 4 on a Windows Azure Website
Looking at Phil's Blog I think what you need is something like:
routes.IgnoreRoute("{*allsvg}", new {allsvg=#".*\.svg(/.*)?"});
Hope that helps.
What order are you declaring the routes? It could be that above that one you have default or catch-all a route that actually already handles the request and so your IgnoreRoute never gets hit.

Manually Enable Compression Using httpModule

I'm trying to enable gzip compression on a site on our work intranet. Unfortunately, I don't have access to IIS, so any changes I make have been through web.config.
The server is running IIS 6 and .NET 2.0.
I enabled compression by adding an httpmodule
public class EnableCompression : IHttpModule
{
public void Init(HttpApplication application)
{
application.BeginRequest +=
(new EventHandler(this.Application_BeginRequest));
}
private void Application_BeginRequest(Object source, EventArgs e)
{
HttpContext context = HttpContext.Current;
context.Response.Filter = new GZipStream(context.Response.Filter, CompressionMode.Compress);
HttpContext.Current.Response.AppendHeader("Content-encoding", "gzip");
HttpContext.Current.Response.Cache.VaryByHeaders["Accept-encoding"] = true;
}
}
I registered in the web.config...
<system.web>
<httpModules>
<add name="EnableCompression" type="EnableCompression"/>
</httpModules>
</system.web>
Well, the above worked fine, except javascript and css files do not get compressed. From what I have found, I would have to add .js and .css to the application mappings in IIS 6, but of course I can't do that.
Apparently this can be done via the web.config file, but I don't know how to do that.
How can I enable compression for .js and .css files?
In IIS6, static code is not processed by managed HttpModules; it requires a native ISAPI.
One trick you can use is to convert your *.js and *.css files into dynamic files. You do this by changing them to be *.aspx, and set the ContentType to the right MIME type. For example:
this.Response.ContentType = "application/x-javascript";
The only other trick is to set StyleSheetTheme="" in the Page directive in the markup file. Otherwise, the runtime will insist on a <head> section in the document. You can enable output caching to minimize the performance impact.
I wrote a blog post about this on the JS side, in case it helps (CSS is similar, just with a different MIME type): http://www.12titans.net/p/dynamic-javascript.aspx
Unfortunately, this requires changing the name of your JS and CSS files in your app, but if you want compression and don't have access to IIS, I don't think there's a way around that.
If you want to keep the *.js and *.css extensions, you can do so by adding a handler for them in your web.config. For example:
<compilation>
<buildProviders>
<add extension=".css" type="System.Web.Compilation.PageBuildProvider"/>
</buildProviders>
</compilation>
<httpHandlers>
<add path="*.css" verb="*" type="System.Web.UI.PageHandlerFactory"
validate="true"/>
</httpHandlers>
This helps from a naming perspective, but not performance; the files will still be dynamic -- they are basically *.aspx files, but with a different extension. It also doesn't work correctly with ASP.NET Themes, since pages in the Themes folder can't be dynamic, regardless of their extension.
Adding to #RickNZ's answer:
Be careful about converting to dynamic. IIS is much faster at serving static files than dynamic (kernel mode). Only consider that if your app is dominated by bandwidth concerns.
One other option is to look into CDNs for static content (content delivery networks). Azure, Amazon, Akamai and others offer services. That's a very fast geo-located friendly way of serving static files.

Handling Expires Headers in ASP.Net MVC

I need advice or suggestions on how to add Expires Headers to my CSS, Image and JavaScript files in ASP.Net MVC.
A key issue is that the software is not in a single location. It is distributed to clients who handle the hosting so I would rather have a solution that doesn't require manual configration in IIS unless it's unavoidable!
I googled around and the majority of answers seem to be focused on content that is returned via a controller. Can't do that for JavaScript files though..
Which IIS Version are you using?
If by 'manual IIS configuration' you mean having to open the IIS manager console, IIS 7.5 (and I think 7 as well) allows you to add expires headers to static content using only the web.config:
<system.webServer>
<staticContent>
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="00:30:00" />
</staticContent>
</system.webServer>
You can do something like this by writing a custom handler for your javascript files. In your Web.Config file of your MVC project look for the httpHandlers section. Add something like the following line:
<add verb="GET" path="/YourScriptsFolder/*.js" type="Your.Project.Namespace.And.Custom.Handler, Your.Assembly.Name" validate="false" />
This will force all requests for js files in that folder through your custom handler which will look something like this:
class CustomHandler : IHttpHandler
{
#region IHttpHandler Members
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
// Set any headers you like here.
context.Response.Expires = 0;
context.Response.Cache.SetExpires(DateTime.Parse("3:00:00PM"));
context.Response.CacheControl="no-cache";
// Determine the script file being requested.
string path = context.Request.ServerVariables["PATH_INFO"];
// Prevent the user from requesting other types of files through this handler.
if(System.Text.RegularExpressions.RegEx.Match(path, #"/YourScriptsFolder/[^/\\\.]*\.js"))
context.Response.Write(System.IO.File.ReadAllText(path));
}
#endregion
}
I haven't tested this code so you might run into some issues but this is the basic idea. There are a plethora of examples on ASP.Net custom handlers throughout the web. Here's a good example:
http://www.developer.com/net/asp/article.php/3565541/Use-Custom-HTTP-Handlers-in-Your-ASPNET-Applications.htm
Another, less complicated option is to add a randomized or versioned query string to the end of the file path.
<link rel="stylesheet" type="text/css" href="somecssfile.css?version=1.0.0.3" />
When you change the version, the browser will get a new copy of the file.

Custom VirtualPathProvider not being used in IIS6

I added the following lines to Application_Start method in global.asax:
var provider = new TestVirtualPathProvider();
HostingEnvironment.RegisterVirtualPathProvider(provider);
Yet the 'TestVirtualPathProvider' is never used when deploying this application in IIS6 (it does in the ASP.NET Development Server).
Edit: the default path provider has always done its job correctly and served (non-embedded) views correctly. The problem is simply that I want to use my own path provider to provide embedded views. So, initially, I already had the following wildcard mapping configured:
Any possible reasons why this does not work in IIS6?
Are there any other factors (handlers for example) wich might influence the used VirtualPathProvider?
UPDATE: the fact that you want to handle extension-less URL's is an important point that's not mentioned in the question. Please see this page for help in setting up MVC with IIS 6: http://haacked.com/archive/2008/11/26/asp.net-mvc-on-iis-6-walkthrough.aspx. This should cover your scenario as well.
Most likely the same issue that I answered in this thread: http://forums.asp.net/t/995633.aspx
Basically, add this in your web.config:
<httpHandlers>
<add path="*" verb="GET,HEAD,POST" type="System.Web.StaticFileHandler" validate="true" />
</httpHandlers>
That other thread has some details that explain why this is necessary.
For the combination Custom VPP + IIS6 + Precompiled site, we need to add the VPP from AppInitailize();
public static class AppStart
{
public static void AppInitialize()
{
// code to be executed automatically by the framework
}
}
See also:
http://sunali.com/2008/01/09/virtualpathprovider-in-precompiled-web-sites/
I believe that you need to use an ISAPI filter in IIS6 to intercept URLs without extensions. Problem is that ISAPI will need to be done in c/c++.
IIS6 is configured to allow only certain extensions to be processed by the ASP.net pipeline.
To findout how you can redirct requests check out the post by DocV.

Resources