ASP .Net MapRequestHandler slow - c#

We have rolled out a classic ASP.Net WebService application with large traffic. Though our database is running quite well (<10 ms response times), most of the time spent in WebServer is in the MapRequestHandler stage.
The issue seems to be deep in the ASP .Net stack and without any information available on net, I am clueless as to how to go about improving it.
We use XML payloads for request/response (if that would help in providing a solution).

Please post you handler code and your config files.
MapRequestHandler - The MapRequestHandler event is used by the ASP.NET infrastructure to determine
request handler for the current request based on the file-name extension of the requested resource. MapRequestHandler is an event that the handlers need to implement, I suspect its stuck at some delegate that maps some custom file.
I suspect its 1) Not finding, looping around to find that custom file handler, you may not 2) using the async handler
You have to chase down the various delegate that use this event and setup a break point
Make sure they are Async & Registered for e.g.
<add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory" />
<add verb="*" path="*.config" type="System.Web.HttpForbiddenHandler" />
<add verb="*" path="*.asmx" type="System.Web.Services.Protocols.WebServiceHandlerFactory" />
Then under the handlers verify
<httpHandlers>
<add verb="*" path="*.MyCustomaspx" type="MyCustomHTTPhandler"/>
</httpHandlers>
In your implementation use the async version base handler
// dervie from Async HttpTaskAsyncHandler
public class MyCustomHTTPhandler: HttpTaskAsyncHandler {
public override Task ProcessRequestAsync(HttpContext context)
{
//throw new NotImplementedException();
//blah blah.. some code
}
}
Last resort, not recommended - from SO here, if your handler/page doesnt modify session variables, you can skip the session lock.
<% #Page EnableSessionState="ReadOnly" %>
If your page does not read any session variables, you can opt out of this lock entirely, for that page.
<% #Page EnableSessionState="False" %>
If none of your pages use session variables, just turn off session state in the web.config.
<sessionState mode="Off" />
Based on this if you want to customize session state just based on your specific page/handler
using System;
using System.Web;
public class CustomSessionStateModule : IHttpModule
{
public void Dispose(){ //.. }
public void Init(HttpApplication context){
context.BeginRequest += new EventHandler(context_BeginRequest);
}
void context_BeginRequest(object sender, EventArgs e){
HttpContext currentContext = (sender as HttpApplication).Context;
// here you can filter and turn off/on the session state
if (!currentContext.Request.Url.ToString().Contains("My Custom Handler or Page Value")){
// for e.g. change it to read only
currentContext.SetSessionStateBehavior(
System.Web.SessionState.SessionStateBehavior.ReadOnly);
}
else {
//set it back to default
currentContext.SetSessionStateBehavior(
System.Web.SessionState.SessionStateBehavior.Default);
}
}
}

Related

How do I restrict POST access to a HttpHandler?

I have a few http handlers (IHttpHandler) in my asp.net web project. Now I want to restrict access to these handlers. For Handler1 I want to allow only POST requests, and for Handler2 I want to allow only GET requests.
In my web.config I modified the <httpHandlers> section as shown below, but both handlers still process all verb types. Is there something I've missed? I'm testing it using IIS Express.
<httpHandlers>
<add verb="POST" path="Handler1.ashx" type="MyNamesapce.Handler1, MyAssembly"/>
<add verb="GET" path="Handler2.ashx" type="MyNamesapce.Handler2, MyAssembly"/>
</httpHandlers>
The reason this isn't working for you is that you've conflated two slightly different "flavours" of something that implements IHttpHandler.
There are two ways that you can implement an IHttpHandler with asp.net:
Create a class that implements IHttpHandler, e.g. MyCustomHandler.cs. This type of handler won't respond to any requests without being configured in your web.config file.
Create an .ashx file (which it looks like you've done), e.g. MyOtherHandler.ashx. This type of handler will respond to any requests to its URL, e.g. http://localhost/MyOtherHandler.ashx
The first type requires entries in the web.config file to work, the second doesn't. This is why you're seeing your .ashx handlers responding to all HTTP verbs, because they're being handled by the part of the asp.net framework that responds to requests for .ashx files, rather than being triggered by your web.config file. If you're using IIS Express, you can see this configured in the file %USERPROFILE%\Documents\IISExpress\config\applicationhost.config. Search for ".ashx" and you'll find a line similar to the below in the <system.webServer><handlers> section:
<add name="SimpleHandlerFactory-Integrated-4.0" path="*.ashx"
verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.SimpleHandlerFactory"
preCondition="integratedMode,runtimeVersionv4.0" />
This is equivalent to what you've been adding to your web.config, but is responsible for telling IIS/asp.net "respond to any URLs that end in .ashx with any of the listed verbs by having the code in the type System.Web.UI.SimpleHandlerFactory deal with it. This code then loads your .ashx file.
To create a handler that can respond to any address you choose, you need (in short) a .cs file containing something similar to:
using System.Web;
namespace HttpHandlers
{
public class Handler4 : IHttpHandler
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
context.Response.Write("Hello World from Handler4.cs");
}
}
}
You can then wire it into your web.config file with:
<add name="Handler4" verb="POST" path="Handler4.ashx" type="HttpHandlers.Handler4, HttpHandlers" />
NOTE: My project that I created to test this is called "HttpHandlers", hence the type declaration that I've specified in that web.config snippet.

Enable CORS for static resources in ASP .NET MVC?

I've found plenty of resources regarding CORS in Web APIs and for general controllers in ASP .NET MVC.
However, I'm in a situation where I'd like all static resources (CSS and JS files) inside a specific folder to be downloadable through AJAX as well. In other words, enable CORS for those resources or that folder.
How can I accomplish this? I've found no similar question. They are all related to web APIs or general controllers.
Example adapted from Walkthrough: Creating and Registering a Custom HTTP Module. This should add the header to all .js and .css requests.
Create Module
using System;
using System.Web;
public class HelloWorldModule : IHttpModule
{
public HelloWorldModule()
{
}
public String ModuleName
{
get { return "HelloWorldModule"; }
}
// In the Init function, register for HttpApplication
// events by adding your handlers.
public void Init(HttpApplication application)
{
application.BeginRequest +=
(new EventHandler(this.Application_BeginRequest));
}
private void Application_BeginRequest(Object source,
EventArgs e)
{
// Create HttpApplication and HttpContext objects to access
// request and response properties.
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
string filePath = context.Request.FilePath;
string fileExtension =
VirtualPathUtility.GetExtension(filePath);
if (fileExtension.Equals(".css") || fileExtension.Equals(".js"))
{
context.Response.AddHeader("Access-Control-Allow-Origin", "*");
}
}
public void Dispose() { }
}
To register the module for IIS 6.0 and IIS 7.0 running in Classic mode
<configuration>
<system.web>
<httpModules>
<add name="HelloWorldModule" type="HelloWorldModule"/>
</httpModules>
</system.web>
</configuration>
To register the module for IIS 7.0 running in Integrated mode
<configuration>
<system.webServer>
<modules>
<add name="HelloWorldModule" type="HelloWorldModule"/>
</modules>
</system.webServer>
</configuration>
As you are running MVC, make sure you alter the one in the root (not the Views folder).

HttpModule doesn't capture ThreadAbortException from WebMethod (aspx or asmx)

I have an HTTPModule:
public class MyErrorModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.Error += new EventHandler(Application_Error);
}
public void Application_Error(object sender, EventArgs e)
{
// Handle error
}
}
It is declared (IIS7.5 Integrated) in web.config:
<system.webServer>
<!-- some more stuff -->
<modules runAllManagedModulesForAllRequests="true">
<add name="ApplicationErrorModule" preCondition="" type="xxxxx"/>
</modules>
<!-- some more stuff -->
</system.webServer>
I tried without the runAllManagedModulesForAllRequests="true" too
I have a WebMethod in a normal webs.aspx.cs (it is part of a big project and I hope I don't have to move everything in an asmx...):
[WebMethod]
public static Model.Response GetDetails(string email)
{
// Do some stuff and return JSON data
}
I call using JQuery and AJAX to POST
https://servername/webs.aspx/GetDetails
In normal situation (without unhandled Exception) things are fine, web-service return what I need. But there are cases I need to call code in a DLL that can do a
Context.Redirect(page,true);
which generates a ThreadAbortException
I was hoping that the HttpModule would help but when the THreadAbortException occurs it doesn't go in the module.
I followed some suggestions to use
<customErrors mode="Off" />
but it doesn't help.
Where is it caught by ASP.Net? I am using 4.0. How can I capture the exception in the Handler?
I see a jsonerror=true in the HTTP Response Header, which makes me thing there is another place it is caught. I don't see other custom module that would catch the exception.
UPDATE
I tried with a webs.asmx webservice with proper annotation (ScriptService etc...) and I still can't capture the ThreadAbortException

How to redirect user while an error happens during OnApplicationStarted?

I am doing a system version comparison during OnApplicationStarted method in Global.asax which does not allow the system boot up if the database version and system version are not matching.
So it looks like this:
protected override void OnApplicationStarted()
{
try{
if(systemVersion != dbVersion)
throw new Exception("They are not same!");
}
catch{
//do some other things
//Response.Redirect("~/VersionError.html");
}
}
but it says "Response is not available in this context." I tried to catch the error in Application_Error but I got the same error.
My question is that how I can redirect users to an error page from within these methods?
Edit:
I know there is no Response at this time but I was asking how to get around this problem. And also one of the reasons why I can hit methods after OnApplicationStarted is that we don't want to load many things if this exception occurs.
Since you don't have access to the Response when the application starts but want all incoming requests to go to an error page if a condition is met, you need to set up something farther up the pipeline. Think IIS modules. Install a module via the following:
<system.webServer>
<modules>
<add name="VersionsNotSameHandler"
type="Company.Exceptions.VersionsNotSameHandler, Company.Exceptions"
preCondition="managedHandler" />
</modules>
</system.webServer>
Now for the module code:
namespace Company.Exceptions
{
public class VersionsNotSameHandler: IHttpModule
{
public void Dispose() { }
public void Init(HttpApplication application)
{
context.PreRequestHandlerExecute += newEventHandler(OnPreRequestHandlerExecute)
}
public void OnPreRequestHandlerExecute(Object source, EventArgs e){
HttpApplication app = (HttpApplication)source;
HttpRequest request = app.Context.Request;
// Check for invalid versioning
app.Response.Redirect('.html page displaying error', true);
}
}
}
The OnPreRequest occurs before every request, making sure that the versions are always checked...you may want to cache if you notice things slowing down.
There is no response at this point you are in application start! This is when the application is starting not when a response is being made.
You could set something in here to direct every url to an error page if this condition is met by setting up a default route which will catch all requests. This would kind of give you the functionality you want as future requests would then get an error page.
Can you just throw an HTTP error:
throw new HttpException(403, "Forbidden");
And then in your web.config:
<customErrors mode="On">
<error statusCode="403" redirect="~/VersionError.html"/>
</customErrors>

Url Rewriting of aspx page.pls give me suggestion

I am new in asp.net. I have iis version 6.0. I want to rewrite url. Actually I'm working on a site. When I used this tag in web.config
<urlrewritingnet
rewriteOnlyVirtualUrls="true"
contextItemsPrefix="QueryString"
defaultPage="default.aspx"
defaultProvider="RegEx"
xmlns="http://www.urlrewriting.net/schemas/config/2006/07" >
<rewrites>
<add name="this-is-a-long-page-name" virtualUrl="^~/this-is-a-long-page-name"
rewriteUrlParameter="ExcludeFromClientQueryString"
destinationUrl="~/Default.aspx"
ignoreCase="true" />
</rewrites>
</urlrewritingnet>
When I run it, it shows the error "unrecognized configuration section rewriter".
user ,
you need to implement urlrewritemodule , all the requests comes to the urlrewritemodule.
you can write your logic there
public class UrlModule : IHttpModule
{
public virtual void Init(HttpApplication application)
{
application.BeginRequest += new EventHandler(this.BaseUrlModule_BeginRequest);
}
public virtual void Dispose()
{
}
protected virtual void BaseUrlModule_BeginRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
Rewritethepath(application.Request.Path, application);
}
private void Rewritethepath(string requestedPath, HttpApplication application)
{
application.Context.RewritePath("/yournewurl", String.Empty, QueryString);
}
}
make this entry in your web.config
<httpModules>
<add type="namespace.UrlModule, namespace" name="UrlModule"/>
</httpModules>
Register your httpmodule in your web.config , once everyrequest comes to this you can rewrite the url however you want ,
i recently implemented this and let me know if you need any help, I will defiently help you.
My response doesn't directly answer your question (which is about the UrlRewritingNet library). Instead, I suggest considering Microsoft's official IIS URL Rewrite library, which requires IIS 7.x or IIS Express. The UrlRewritingNet library, though useful a couple years ago, is now a less than ideal way to go about rewriting URLs in IIS/ASP.NET. I offer this suggestion since you mentioned you are new to ASP.NET. :)

Categories