I create an IIS Module that appends text to the page before it loads. When I go to the URL, this works perfect the first time the page loads. On subsequent loads, however, the text is never appended.
Any thoughts on how to remedy this?
== CODE ==
Here's my web.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<system.webServer>
<modules>
<add name="MIModule" type="MI.MyModule, MI" />
</modules>
<caching enabled="false" enableKernelCache="false" />
</system.webServer>
</configuration>
Some module code:
public void context_PreRequestHandlerExecute(Object source, EventArgs e)
{
HttpApplication app = (HttpApplication)source;
HttpRequest request = app.Context.Request;
string pageContent = app.Response.Output.ToString();
string useragent = "HI!<br />" + pageContent + "<hr />" ;
try
{
_current.Response.Output.Write(useragent);
}
catch
{
}
}
and the rest of the code:
private HttpContext _current = null;
#region IHttpModule Members
public void Dispose()
{
throw new Exception("Not implemented");
}
public void Init(HttpApplication context)
{
_current = context.Context;
context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);
}
#endregion
Is the _current variable actually HttpContext.Current? Is it a static field in your module? When/how is it initialized? My guess is that the empty catch clause gobbles up all errors, and following that thought, you most probably get a null reference on _current. Try removing the try/catch to learn more on what's wrong with your code
Related
I have an Asp.Net Web Api project, and i am trying to create a simple IHttpModule for logging errors.
The module gets loaded correctly, because i could register to BeginRequest / EndRequest events. However, the Error event is never triggered.
I have also added and removed the runAllManagedModulesForAllRequests="true" attribute from web.config, but still with no effect.
public class ErrorLogModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.Error += Context_Error;
}
// method never triggered
private void Context_Error(object sender, EventArgs e)
{
HttpContext ctx = HttpContext.Current;
Exception exception = ctx.Server.GetLastError();
// todo
// log Exception
}
public void Dispose()
{
}
}
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="ErrorLogger" type="HttpModules.HttpModules.ErrorLogModule" />
</modules>
</system.webServer>
[HttpGet]
[Route("triggerError")]
public string TriggerError()
{
int test = 0;
var a = 1 / test;
return "Hello Workd";
}
You can use better logging approach, that 100% working.
See this Microsoft article.
Shortly speaking you can implement
YourExceptionLogger: ExceptionLogger
with just one override method and register it by
config.Services.Add(typeof(IExceptionLogger), new YourExceptionLogger());
I write a custom handler to handle requests with OPTIONS verb.
public class OptionsRequestHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string origin = context.Request.Headers.Get("Origin");
context.Response.AddHeader("Access-Control-Allow-Origin", origin);
context.Response.AddHeader("Access-Control-Allow-Methods", "*");
context.Response.AddHeader("Access-Control-Allow-Headers", "accept, authorization, content-type");
}
public bool IsReusable
{
get { return false; }
}
}
And have registered this handler in web.config.
<system.webServer>
<modules>
......
</modules>
<handlers>
......
<add name="OptionsHandler" path="*" verb="OPTIONS" type="REAMS.Infrastructure.RequestHandlers.OptionsRequestHandler"/>
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,POST,DELETE,PUT,HEAD" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
But the handler is never selected for options requests. Is there anything wrong? Thanks!
Finally figured out this problem. Because, by default, MVC framework map request to a handler by path, it is not possible to map a handler to a request by the request verb.
To do this, I will need to preempt the handler selection of MVC and implement my own module. Here is a working copy for anyone interested.
public class OptionsVerbModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.PostRequestHandlerExecute += onPostRequestHandlerExecute;
context.PostResolveRequestCache += onPostResolveRequestCache;
}
private void onPostResolveRequestCache(object sender, EventArgs eventArgs)
{
if (string.Equals(HttpContext.Current.Request.HttpMethod, "OPTIONS", StringComparison.OrdinalIgnoreCase))
{
HttpContext.Current.RemapHandler(new OptionsRequestHandler());
}
}
private void onPostRequestHandlerExecute(object sender, EventArgs e)
{
string origin = HttpContext.Current.Request.Headers.Get("Origin");
if (origin != null)
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", origin);
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Credentials", "true");
}
}
public void Dispose()
{
}
}
What the module does is to check the verb of the request and if it is of 'OPTIONS' request, selected my customized handler in the question rather than map to MVC handler.
I do this because I find existing EnableCors for Web API is not suitable for my application needs and by using this customized process I have more control as well.
I would like to handle static file web requests through an HttpModule to show the documents in my CMS according to some policies. I can filter out a request, but I don't know how to directly process such a request as asp.net should do.
Is this what you're looking for? Assuming you're running in integrated pipeline mode, all requests should make it through here, so you can kill the request if unauthorized, or let it through like normal otherwise.
public class MyModule1 : IHttpModule
{
public void Dispose() {}
public void Init(HttpApplication context)
{
context.AuthorizeRequest += context_AuthorizeRequest;
}
void context_AuthorizeRequest(object sender, EventArgs e)
{
var app = (HttpApplication)sender;
// Whatever you want to test to see if they are allowed
// to access this file. I believe the `User` property is
// populated by this point.
if (app.Context.Request.QueryString["allow"] == "1")
{
return;
}
app.Context.Response.StatusCode = 401;
app.Context.Response.End();
}
}
<configuration>
<system.web>
<httpModules>
<add name="CustomSecurityModule" type="MyModule1"/>
</httpModules>
</system.web>
</configuration>
1- I have a class structure as shown below.
namespace ViewStateSeoHelper
{
class ViewStateSeoModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
}
void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication application = sender as HttpApplication;
if (application.Context.Request.Url.AbsolutePath.Contains(".aspx"))
application.Response.Filter = new HtmlFilterStream(application.Response.Filter);
}
public void Dispose()
{
}
}
}
I'm using something like this to using in all those pages through upper code.
<httpModules>
<add name="ViewStateSeoModule" type="ViewStateSeoModule" />
</httpModules>
But,I got the configuration error.
Parser Error: Could not load type 'ViewStateSeoModule'.
(C:\Users\xxx\Documents\Visual Studio 2010\WebSites\xxx\web.config
line 78) Line 78:
Thanks in advance.
You have wrapped your code in a namespace but not referred to it in the web.config:
<httpModules>
<add name="ViewStateSeoModule" type="ViewStateSeoHelper.ViewStateSeoModule" />
</httpModules>
The type attribute needs to include your namespace. Try:
<httpModules>
<add name="ViewStateSeoModule" type="ViewStateSeoHelper.ViewStateSeoModule" />
</httpModules>
I have developed my asp.net website in .NET 2.0 in other system where it is working fine. Now when I copied the asp.net website in my system and run it than I am getting the run time error:
Object reference not set to an
instance of an object.
public class FixURLs : IHttpModule
{
public FixURLs()
{
}
#region IHttpModule Members
public void Dispose()
{
// do nothing
}
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
context.CompleteRequest();
}
..... some other logic
I am getting object reference error at the line:
context.CompleteRequest();
My web.Config file has
<compilation debug="true">
<assemblies>
<add assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</assemblies>
</compilation>
How can I fix this issue?
EDIT
Edit Note New code added
void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
if (app.Request.RawUrl.ToLower().Contains("/bikes/default.aspx"))
{
app.Context.RewritePath("BikeInfo.aspx", "", "");
}
else if (app.Request.RawUrl.ToLower().Contains("/bikes/mountainbike.aspx"))
{
app.Context.RewritePath("BikeInfo.aspx", "", "ItemID=1");
}
}
I strongly suspect that you would want to put completerequest at the end of the context_beginrequest method because right now this doesn't really make sense. If that isn't the case please post that method as well so it's clear what you are trying to do.
EDIT: It looks like your intention is to do this:
void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
if (app.Request.RawUrl.ToLower().Contains("/bikes/default.aspx"))
{
app.Context.RewritePath("BikeInfo.aspx", "", "");
app.CompleteRequest();
}
else if (app.Request.RawUrl.ToLower().Contains("/bikes/mountainbike.aspx"))
{
app.Context.RewritePath("BikeInfo.aspx", "", "ItemID=1");
app.CompleteRequest();
}
}
It doesn't look like you'd want to call CompleteRequest unless you are actually doing something in BeginRequest. And to be clear, in your original code, you are calling CompleteRequest before the BeginRequest event even fires.
I think you should just leave out your call to context.CompleteRequest();
This is normally meant to stop the execution of a request, but you're calling it when your application is initializing and no requests are being processed. My guess was that in .NET 2.0 it would tolerate this call and not do anything bad, but in a later version it blows up.
It doesn't look to me like you want to stop the request immediately after you've rewritten the URLs... otherwise, why even rewrite them? So just try getting rid of that method call.
void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
if (app.Request.RawUrl.ToLower().Contains("/bikes/default.aspx"))
{
app.Context.RewritePath("BikeInfo.aspx", "", "");
app.CompleteRequest();
}
else if (app.Request.RawUrl.ToLower().Contains("/bikes/mountainbike.aspx"))
{
app.Context.RewritePath("BikeInfo.aspx", "", "ItemID=1");
app.CompleteRequest();
}
}