Custom C# HttpModule Infinite Redirect Loop - c#

I am writing a custom c# HttpModule that will handle requests from all file types. As a simple proof of concept I have setup the module by adding a reference to the httpModules section of the web config and added application extensions for the demo IIS website with a reference to the aspnet_isapi.dll so that it currently only intercepts request for ".htm" files
But even if there is no significant code in the "OnBeginRequest" event (code below) it causes an infinite redirect loop. I am using IIS 5 on XP Anyone got any ideas?
So far I have only seen HttpModule examples for use with ASPX files but surely you can configure the for any file type?
#region IHttpModule Members
public void Dispose() { }
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(OnBeginRequest);
}
///
///
///
///
public void OnBeginRequest(Object s, EventArgs e)
{
HttpApplication context = s as HttpApplication;
Uri currentURL = context.Request.Url;
string pageName = currentURL.Segments.Last().ToLower();
}
#endregion

OK. The problem was actually in the HttpModule itself.
It appears that you have to use the HttpApplication context in order for it to render on the client.
For Example after you have performed all your custom logic you need to write to the context:
context.Response.Write("/n/r");
//or
context.Response.Redirect("test.htm");
Everything then renders as you would expect

Related

Recording events(request & response) in an MVC application

Ok, so I have quite a task here:
The background of this project is very complex and fully covered by NDA's so I'll just state what I am trying to do without the background.
So what I need is a way to record every request made to an MVC application and every response from it.
Furthermore, I also need a way to "reply" the requests exactly as they were sent.
I was hoping that I could create some solution that "loads" the MVC application, Self hosts or runs in IIS, get requests, records them and passed them verbatim to the MVC application which would then act exactly like any other MVC app.
I could then create a second solution that "loads" the MVC app but instead of opening it up to request it would read the events from the event store and "replays" them in the MVC app.
Now I have no clue where to even start. This kinda thing is way out of my comfort zone.
If there is another solution for how I can record and replay request (and responses) then please let me know.
Even if there is a way to intercept a request in MVC before it starts doing all of its authentication and routing malarkey then that would be a great starting point. I would also need to know where I can capture the response at the very last second before it is sent.
Many thanks for your time
Andy
A HttpModule would work just fine for your scenario:
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));
application.EndRequest +=
(new EventHandler(this.Application_EndRequest));
}
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;
/*...*/
}
private void Application_EndRequest(Object source, EventArgs e)
{
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
/*...*/
}
public void Dispose() { }
}
The code and more information available here.

ASPX Page Life Cycle when calling [WebMethod]s

I'm calling a number of methods that have been decorated with [WebMethod] via jQuery ajax.
These require a database connection to be set up in an external library that will be the same for each method.
My original code looked like this:
public partial class Server : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// code to set up DB connections
ExternalLibrary.SetupDB();
}
[WebMethod]
public static string AjaxAccessibleMethod()
{
try
{
// get some data from the database via the external library
ExternalLibrary.CallDatabase();
}
catch(Exception ex)
{
// handle errors
}
}
}
This was working, but then started throwing exceptions claiming that the ExternalLibrary's database hadn't been initialized.
Placing breakpoints in my code I found that the Page_Load event wasn't being called when calling my AjaxAccessibleMethod, I also tried moving the DB setup stuff into the Page_Init event but likewise that wasn't called.
Can anyone explain to me the aspx page life cycle when using WebMethods? The fact that this worked initially seems to imply that Page_Load was called, but it no longer is.
Notice that the method you are using as WebMethod is static, this should be the first hint to the fact that Page object is not created at all.
Page Methods is a simple alternative to full blown web services, and as such, its life cycle is more similar to web service than to page. That is, request goes through the general ASP.NET pipeline, with objects like HttpContext, Request and such. But then the difference happens: for page requests and postbacks page object is created and the whole series of page events happens, whereas for page methods page object is not created, and method is simply called as Server.AjaxAccessibleMethod().
There is really no way to mix the two, because this would unnecessarily complicate processing of calls to page methods. So the only path forward for you here is duplicate necessary code:
protected void Page_Load(object sender, EventArgs e)
{
// code to set up DB connections
ExternalLibrary.SetupDB();
}
[WebMethod]
public static string AjaxAccessibleMethod()
{
ExternalLibrary.SetupDB();
...
}

Is HttpContext.RemapHandler supposed to change which handler processes request?

The MSDN documentation says:
HttpContext.RemapHandler Method - Enables you to specify a handler for the request.
I am trying to move the processing of the request from one handler to another depending on a condition in the first handler. The HttpContext.RemapHandler method seems to initialise an instance of the second handler but not call the HttpHandler.ProcessRequest method; the response is empty.
Does the HttpContext.RemapHandler method do what I think it should - transfer processing to a new HttpHandler and calling the HttpHandler.ProcessRequest method? Or should I be using another approach such as another method or an HttpModule?
EDIT:
Turns out I should be using a HTTPHandlerFactory. I have the solution working nicely now.
So what exactly is HttpContext.RemapHandler for?
You can use HttpContext.RemapHandler as you specified, however if another HttpHandler calls RemapHandler (e.g. ASP.NET MVC which registers MvcHandler in PostResolveRequestCache) your IHttpModule will never fire. This is maybe why IHttpHandler.Process was never called.
If this is your issue, you can simply define a route to ignore in MvcApplication.RegisterRoutes like this:
routes.IgnoreRoute("your_path/{*pathInfo}");
Also, remember that with Visual Studio Web Development Server and IIS6, RemapHandler will not work.
Here is an example of how to select the right way to remap the handler based on whether or not Integrated Pipeline is activated AND still be able to access the session:
public void Init(HttpApplication application)
{
if (HttpRuntime.UsingIntegratedPipeline)
// For IIS 7 and IIS 8
application.PostAuthorizeRequest += Application_PostAuthorizeRequest;
else
// For IIS 6
application.PostMapRequestHandler += Application_PostMapRequestHandler;
}
private void Application_PostAuthorizeRequest(object sender, EventArgs e)
{
((HttpApplication)sender).Context.RemapHandler(_myHandler);
}
private void Application_PostMapRequestHandler(object sender, EventArgs e)
{
((HttpApplication)sender).Context.Handler = _myHandler;
}
The difference between using a HttpHandlerFactory and HttpModule in this case is that the latter allows you to decide when to use which IHttpHandler regardless of ASP.NET IHttpHandler mappings. More on MSDN: HTTP Handlers and HTTP Modules Overview.

How would an HttpModule for Custom Authentication interact with Windows Authentication?

I am trying to create a custom HttpModule which controls which users can view a site.
I am trying to leverage Windows Authentication to do this.
On an individual page, I would probably do something like this:
if (HttpContext.Current.User.Identity.Name.Contains("jsmith"))
{
Response.Write("You do not have the correct permissions to view this site.");
Response.End();
}
But because I want to make this more configurable at the application level, I would like to use an HttpModule.
Here is the start that I have made on the code:
using System;
using System.Web;
public class CustomAuthHttpModule : IHttpModule
{
public void Dispose() { }
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(OnBeginRequest);
context.EndRequest += new EventHandler(OnEndRequest);
}
void OnBeginRequest(object sender, EventArgs e) { }
void OnEndRequest(object sender, EventArgs e)
{
HttpApplication appObject = (HttpApplication)sender;
HttpContext contextObject = appObject.Context;
if (contextObject.User.Identity.Name.Contains("jsmith"))
{
contextObject.Response.Clear();
contextObject.Response.End();
}
}
}
I would be fine with using the code I have, if I could put it in the OnBeginRequest() function. But the User property is not created in the HttpContext object until OnEndRequest() runs.
Running the code earlier would prevent the application from doing the extra work of producing this output, since some users are just going to be blocked from access in the end.
Can someone suggest a solution to this - is this happening because my module is running before the Windows Auth module, or what?
... or, maybe there is an easier way to do what I am trying to do with IIS or file system permissions?
You want the AuthenticateRequest event.
AuthenticateRequest event
Have you tried to implement the method in the global.aspx? OnSessionStart?
Besides I would use hasRole or some other group-Property instead of contains and username.
Why write an http module for this. If this is asp.net web forms then why not simply use built in stuff like LoginView http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.loginview.aspx

Unit Testing Application_Start

I am looking for any kind of information (prefer Moq) on how to unit test the Application_Start method in Global.asax. I am using ASP.NET MVC and trying to get to that elusive 100% code coverage!
The fact that I'm using MVC is not the point. And saying that not testing Start is not necessary isn't really the answer either. What if I had other code in there? I need to know how to test it.
Some organizations do require those meaningless numbers, and have issues beyond cost. For companies dealing with $ensitive information "Good enough" is not good enough. I had exactly the same issue and like Klas Mellbourn, need to get to 100% (if not higher!)
The following worked for me. Although, I'd have preferred to mark it "Exclude from code coverage"
public class Global : HttpApplication
{
public override void Init()
{
AreaRegistration.RegisterAllAreas(); //will error out on app_start
base.Init();
}
/// <summary>
/// Application_Start method.
/// </summary>
/// <param name="sender">The caller</param>
/// <param name="e">The event arguments</param>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "KMM: This method is called dynamically by the framework.")]
protected void Application_Start(object sender, EventArgs e)
{
var container = StructureMapRegistry.Initialize();
GlobalConfiguration.Configuration.DependencyResolver = new StructureMapResolver(container);
GlobalConfiguration.Configure(WebApiConfig.Register);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
}
Then the unit test looked like this:
public class GlobalTest : Global
{
private HttpRequestMessage FakeRequest;
DateTime? effectiveDate = DateTime.Now.AddYears(-4);
private string policyNumber = "1234567890";
[TestMethod]
public void ApplicationStart()
{
var sender = new object();
var e = new EventArgs();
try
{
Application_Start(sender, e); // this will error b/c not fully loaded yet.
}
catch (InvalidOperationException)
{
Thread.Sleep(2000); // give the app time to launch
Application_Start(sender, e);
}
Assert.IsTrue(true);
}
}
and finally, I needed to set a flag in my WebApiConfig to prevent the routes from being registered twice.
public static class WebApiConfig
{
private static bool isRegistered;
/// <summary>
/// Registers the configuration.
/// </summary>
/// <param name="config">The Http Configuration.</param>
public static void Register(HttpConfiguration config)
{
if (isRegistered)
{
return;
}
config.MapHttpAttributeRoutes();
Now, before the haters and purists start marking this down, the assignment is to test all code. I personally detest modifying code to suit tests. That's not the same thing as making code testable. Adding the isRegistered flag is an example of the sort of artifact that is necessary to support the test needing to call the app_start 2x. It's a small thing and since that code only gets called on app_start, I'm not going to fuss over it too much.
I would certainly be interested in what others have done in this regard.
In a typical ASP.NET MVC application the Application_Start event is often used to register custom routes. Here's a nice post explaining how to unit test your custom routes.
this function is called the first time your site is visited.
recycling the app pool will cause it to be triggered again
In most situations, this event handler has no code, so don't waste time pursuing meaningless numbers!
If you want to test the actions of an event-based item like this, separate the actions into a separate, testable method and just call it from the handler. Or, as darin suggested, test the effects of the method - in this particular case, that your routing table got registered correctly.
BTW, I've never reached 100% coverage on a non-trivial app... We generally target 80% as "good enough". Some modules are 100% testable, but many aren't practical to do so.
I've found the best way to unit test stuff in Global.asax is to make sure the whole thing is in a testable static method.
Then pass in to that method everything it needs from Global.asax.
So for example, if you were doing a check of Session on Application Start, you could have a method like this:
public static void CheckSession(HttpSessionStateBase session)
{
...
}
Then, your Application Start would just be this:
protected void Application_Start(object sender, EventArgs e)
{
CheckSession(new HttpSessionStateWrapper(Session));
}
This example is obviously a little silly as you'd probably do something like this in Session Start :) You could pass into that method whatever it needs, Request, Response, Cache, etc.
However, it gets the point across. The only code that wouldn't be covered would be the actual single line call in Application_Start. Everything else could be covered in a test using Moq like so:
var session = new Moq<HttpSessionStateBase>();
...Set Expectations...
Global.CheckSession(session.Object);
...Do Asserts...
You wouldn't achieve the 100% code coverage you're looking for, but you'd be darned close, and you would be fulfilling the "spirit" of TDD law if not exactly the letter :)

Categories

Resources