IHttpModule and threading - c#

I have a class that implements IHttpModule. This is a support class to help my application defend against DDOS attacks. After implementing the BeginRequest method, I tried to debug my code and for some reason, each time that I debug the class, I have multiple threads in Visual studio. I can't understand why, all of the sudden, while running this application on my local machine, I'm getting several threads, and it happens only in this class.

The HttpModule probably intercepts all requests to your application, including files (js, css, images, etc.)
Take a look at the Request object of each request, and look at the Url property to see what is happening.
Edit:
HttpModules are active very early in the request flow, and they will often get hit by most requests for the server, so keep the code in the HttpModule to a minimum. An example: if you're making permissions on files, make sure the request is actually hitting a file (ie. the requested url starts with /files/). Whenever possible, cache data for use in HttpModules, don't go to the database for each and every request in a HttpModule!
The reason why you probably get less hits in your actual application, is that even requests for images, js files, css files, etc. might make a hit in the HttpModule, but in your application, only requests meant for the application will hit your break points (aspx, asmx, etc. for Web Forms and recognized routes in ASP.NET MVC).
To get a look at what requests you're handling in a HttpModule, look at the value of the url variable:
void context_BeginRequest(object sender, EventArgs e) {
HttpApplication app = (HttpApplication)sender;
String url = app.Request.Url.OriginalString;
}

Related

how to send a request to one of the IIS handlers programatically?

i have a legacy 3rd party application which submits data to our internal sales system. It exposes ASP page with a form to the internet as follows:
<form id="ServiceRequest" enctype="multipart/form-data" method="post" action="AddToServiceRequest.csp">
where AddToServiceRequest.csp is a proprietary IIS handler:
Right now we embed this form into our ASP.Net 4 website using iframe - and that is really inconvenient. What I want to do is to replace this form with a native form, do all validation etc - and then call AddToServiceRequest.csp handler from code-behind logic. What's the right way to do it? I can think only about something like this:
var r = (HttpWebRequest)WebRequest.Create("http://localhost/AddToServiceRequest.csp");
r.Method = "POST";
r.KeepAlive = false;
// fill in form data
var res = r.GetResponse();
res.Close();
but it just does not look "right" to me. Are there any other ways?
If handler serving request is for some other site (from IIS point of view) than code for it will run in separate process or separate AppDomain and you will have no reasonable way to call it directly.
If handler is registered for the same site as yours you may be able to invoke it directly - i.e. if it is APS.Net class that handles request than it just an interface with couple methods - you may be able to instantiate and execute it directly. Note that many handlers depend on HttpContext.Current and you may not be able to set request reasonably for such calls.
It is also unlikely to register same handler to your site as most handlers/controllers/forms are designed to work for particularly configured site (i.e. Web.Config will have DB connection info).
So making direct web request is most straightforward solution. I would not try any other way as most web code will not handle unusual ways of invocation correctly.
You may consider HttpClient instead of WebRequest to get easier async supoprt (assuming .Net 4.5+), but any way of setting up request is ok.
Note that if site uses Windows Authentication you may not be able to pass user information via Web request .

Keeping ASP.NET Session alive

With our current setup there is a requirement to maintain mirrored sessions between two sites, one existing ASP.NET website hosted in IIS 6.0 which is now containing the new website in an iFrame, and hosted seperately in IIS 7.5 (It's MVC3).
Does anyone have any suggestions as how to keep the parent session in line with the child website session?
My initial thought was to create an ActionFilter to fire a HttpWebRequest to an HTTPHandler of sorts on the parent site on the OnActionExecuting method. There has been doubts raised as to how this would keep the specific sessions inline, perhaps missing knowledge about session ID's of sorts?
Something like:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
try
{
var request = WebRequest.Create(
ConfigurationManager.AppSettings["HeartbeatURI"]);
using (var webResponse = request.GetResponse())
{
var response = webResponse as HttpWebResponse;
if (response != null && response.StatusCode == HttpStatusCode.OK)
{
Does anyone have any recommendations/ advice here? Thanks!
Update:
After some helpful suggestions I will be investigating whether a solution from the browser, something like:
function setHeartbeat() {
setTimeout("heartbeat()", 300000); // every 5 min
}
function heartbeat() {
$.get(
"http://soemthing:1234/heartbeathandler.ashx",
null,
function(data) {
setHeartbeat();
},
"json"
);
}
Will perform as I require.
There are two fundamental issues your code example is not taking into consideration:
First, sessions are per-client. This solution attempts to 'heartbeat' a single connection from the secondary server. So it won't work.
Second, sessions require client interaction, either via cookies or special, extra URL values. This solution makes no attempt to incorporate those, so no session will be created at all.
EDIT: There's also a third problem: In-process sessions are not guaranteed to stay alive no matter what you do; the application is subject to being recycled at any time, and application recycles will wipe in-process session values. So, you would need to have some external session management system, so that sessions (on both servers) are maintained.
Really, though; it's pretty brittle to try to keep sessions maintained like this. It sounds like it's really important to your application, but there's almost no guarantee it will work all the time. Rearcitecting your application not to require sessions, or to be able to rebuild them on the fly, would be a better option, IMO.

Best way to transfer files through a web service

My C# program communicates with a server using a web service, I need the client to download big files from the server and have the option to pause and continue their download, the downloader must also be authorized to download the file.
I had two thoughts on how to do that,
one is to use some 3rd party API like wget to download the files. the problem with that is that I need to learn the API commands and that I'm not certain I can show my download progress in the program, another issue is that I would have to use use bare URLs to get the files from the server which seems ugly and could lead to people just downloading them off the server (I want them to be authorized, although this isn't a real issue since this is just a school project).
My other thought was to create a method on the web service that will get a position in the file and an amount of bytes and return them and the client will piece them together, it seems more complicated but more compelling since the user must be authorized to download the file and I can use it to show the tester some more advanced programming skills ;). The issue with that looks like it might be performance taxing.
What's your opinion? what's the best way to download big files off a server?
Absent the need for authorization and partial downloads, WebClient.DownloadData or WebClient.DownloadDataAsync would be the preferred method of downloading a file from a server.
You could still use WebClient for the authorization by setting the Credentials in your WebClient object instance. If the user isn't authorized to download the file, based on those credentials, the server can return a 404 (Not found) or 403 (Forbidden).
If your server supports HTTP 1.1, the client can start in the middle of the file. To do so, you'll have to create a class that inherits from WebClient and override the GetWebRequest method. That method would then set the headers to do a positional GET.
class MyWebClient : WebClient
{
public int StartDownloadAt { get; set; }
protected override WebRequest GetWebRequest(Uri address)
{
HttpWebRequest req = (HttpWebRequest)base.GetWebRequest(address);
req.AddRange(position_to_start);
}
}
And in the code that uses it:
MyWebClient client = new MyWebClient();
client.StartDownloadAt = 1024 * 2024; // start download 1 megabyte into file.
client.DownloadData(...);
The above is just an example. You'd probably want to make that more robust by having the StartDownLoadAt property reset to 0 when a download is done (or aborted), and not do the AddRange if StartdownloadAt is set to 0. To fully support ranges, you'd probably want properties for start and end range, etc.
And, of course, the client will have to handle stitching the disparate downloaded pieces together after download is complete.
The point is that it should be possible, with a little work, by using the WebClient class.

Static files and authentication in ASP.net

Say I have a virtual folder /topFolder/ in IIS7, and in that folder there can be any file that can be displayed in a browser (xml, html, swf, doc etc - typically "unmanaged" resources from the IIS perspective).
Before giving the request permission to open any file below the folder, I need to check some session variables in order to see if the user has a "license" for the subfolder and file in question.
I've tried implementing a module with IHttpModule and IReadOnlySessionState interfaces, but the Session is always null on the AcquireRequestState event when the file is "static" and not IIS managed (like aspx, ashx etc).
If I use a custom HttpHandler, I get the session, but then I also need to implement how the content is sent to response. Edit: Since the user isn't downloading the file, I just want IIS to serve the file like it does with its StaticFileModule. The Handler/Module should really be a StaticFileModuleWithAuthorizationHook...
So I really want to do the following:
1. For request /topFolder/* : check session and licenses etc
a) If ok, continue serving file
b) If not ok, interrupt request, or just send FORBIDDEN in response.
Hope someone can help.
You should be able to handle this via the httphandler, the simple way is to use the built in methods to send the file down to the user if they have access.
This article (at the bottom) shows an example of how to do this.

IIS7, RewritePath and IIS log files

I am using Context.RewritePath() in ASP.NET 3.5 application running on IIS7.
I am doing it in application BeginRequest event and everything works file.
Requests for /sports are correctly rewritten to default.aspx?id=1, and so on.
The problem is that in my IIS log I see GET requests for /Default.aspx?id=1 and not for /sports.
This kind of code worked perfectly under IIS6.
Using Microsoft Rewrite module is not an option, due to some business logic which has to be implemented.
Thanks.
EDIT:
It seems my handler is too early in the pipeline, but if I move the logic to a later event, than the whole rewrite thing doesn't work (it's too late, StaticFileHandler picks up my request).
I googled and googled, asked around, can't believe that nobody has this problem?
EDIT:
Yikes! Here's what I found on the IIS forum:
"This is because in integrated mode, IIS and asp.net share a common pipeline and the RewritePath is now seen by IIS, while in IIS6, it was not even seen by IIS - you can workaround this by using classic mode which would behave like IIS6."
Final update: Please take a look at my answer below, I've updated it with results after more than a year in production environment.
After some research, I've finally found a solution to the problem.
I have replaced the calls to Context.RewritePath() method with the new (introduced in ASP.NET 3.5) Context.Server.TransferRequest() method.
It seems obvious now, but not event Senior Dev Engineer on IIS Core team thought of that.
I've tested it for session, authentication, postback, querystring, ... issues and found none.
Tommorow I'll deploy the change to a very hight traffic site, and we'll soon know how it actually works. :)
I'll be back with the update.
The update: the solution is still not entirely on my production servers but it's tested and it does work and as far as I can tell so far, it's a solution to my problem. If I discover anything else in production, I will post an update.
The final update: I have this solution in production for over a year and it has proven to be a good and stable solution without any problems.
You could set the path back to the original value after the request has been processed but before the IIS logging module writes the log entry.
For example, this module rewrites the path on BeginRequest and then sets it back to the original value on EndRequest. When this module is used the original path appears in the IIS log file:
public class RewriteModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += OnBeginRequest;
context.EndRequest += OnEndRequest;
}
static void OnBeginRequest(object sender, EventArgs e)
{
var app = (HttpApplication)sender;
app.Context.Items["OriginalPath"] = app.Context.Request.Path;
app.Context.RewritePath("Default.aspx?id=1");
}
static void OnEndRequest(object sender, EventArgs e)
{
var app = (HttpApplication)sender;
var originalPath = app.Context.Items["OriginalPath"] as string;
if (originalPath != null)
{
app.Context.RewritePath(originalPath);
}
}
public void Dispose()
{
}
}
I've had exactly the same problem. One way around this is to use Server.Transfer instead of Context.RewritePath. Server.Transfer doesn't restart the entire page lifecycle so the original URL will still be logged. Be sure to pass "true" for the "preserveForm" parameter so that the QueryString and Form collections are available to the 2nd page.
Old question, but I found I did not encounter your problem when I did the following:
a) A rewrite rule in web.config to direct all requests to /default.aspx, eg:
<rule name="all" patternSyntax="Wildcard" stopProcessing="true">
<match url="*"/>
<action type="Rewrite" url="/default.aspx"/>
</rule>
b) Called RewritePath in the Page_PreInit event of default.aspx, to rewrite the URL and querystring as what was passed in the request (ie. the location that doesn't exist).
For example, I request "/somepage/?x=y" (which doesn't exist).
a) Web.config rule maps it to /default.aspx
b) Page_PreInit rewrites it back to "/somepage/?x=y".
The result of this, in IIS 7 (Express and production) is that the server log reflects "/somepage" for stub and "x=y" for query, and all the Request object properties reflect the requested (non-existent) URL (which is what I wanted).
The only weird effect is, in IIS Express, the log item is written twice. However this doesn't happen in production (Windows Server 2008 R2).

Categories