I have a custom error handler class like this:
namespace AccountCenterUserControls
{
public class EWHErrorModule : IHttpModule
{
public void Init(HttpApplication app)
{
app.Error += new System.EventHandler(OnError);
}
public void OnError(object obj, EventArgs args)
{
Page myPage = (System.Web.UI.Page)HttpContext.Current.Handler;
ctx.Server.ClearError();
}
public void Dispose() { }
}
}
I've instantiated this error handler in my web.config like this:
<httpModules>
<!-- EWH Custom Error Handler -->
<add type="AccountCenterUserControls.EWHErrorModule" name="EWHErrorModule"/>
</httpModules>
It traps errors ok. My question is, how can I let my trapped error pages benefit from my masterpage? I can get to the individual masterpages from my page, but I'm not quite sure how I set the contentplaceholder when I am in this deep.
In ASP.NET the app error event can be raised at any point during the page life-cycle you may be executing your error handler at a time it is entirely illegal to modify the Page. If it is allowable you can attain a reference to the element you wish to modify or replace using FindControl. Again, if the timing is legal you can modify the controls collection of the control or add or remove controls from the control's control collection to achive the eventual desired rendering.
I hope my assumptions are correct about your situation If they are I did wonder why you do not simply implement Application_Error in Global.asax/.cs? This would be automatically wired to the ASP.NET application's OnError event. Inside that handler you would have references available to Request, Response, and Session.
Also, you should be aware that HttpContext.Current.Handler can and will return null at certain stages of the life-cycle. For example an error has occurred before the request is handed off to the handler like during authenticate request.
Related
I looked for an answer to this for quite sometime now but didn't find any.
I will refer to Application start as a stage.
Most of the documentations out there talk about the Global.asax file and the Application_Start method which is invoked only once when the first request reaches the Application, even if this behaviour is similar to subscribing to an event it's technicaly not an event.
While lifecycle events such as BeginRequest, AuthenticateRequest and so on are accessible through the application instance as events, the Application.Start is not.
I can subscribe to BeginRequest event in an HttpModule.Init() method or Global.asax Init() method but not to the Application.Start stage like so:
Module
public class MyModule : IHttpModule
{
public void Init(HttpApplication httpApplication)
{
httpApplication.BeginRequest += new EventHandler(ApplicationBeginRequest);
}
}
Global
public class Global : HttpApplication
{
public override void Init()
{
BeginRequest += new EventHandler(ApplicationBeginRequest);
}
}
My question:
Since there is no HttpApplication.Start event accessible from the Application instance, is Global.asax and the "Application_Start" method the only hope to subscribe to the Application start stage ?
After jumping to the .NET source code i found that the HttpApplicationFactory class looks for a method named Application_OnStart or Application_Start in the Global.asax file and then invokes it using reflection => ReflectOnMethodInfoIfItLooksLikeEventHandler().
I don't have the answer why HttpApplication.Start is not event but it's clearly intended to be handled in an event like fashion using Application_OnStart or Application_Start methods.
i have a custom event handler in the page, and it is called by the user controls of it.
everything is fine, except there is error display in the code ( red highlighted), but the program can be compiled, and able to run with no apparent error.
but i want to fix (or understand) the reason why the visual studio showed error for that
the error is
the code is
-PAGE
Operator_agentcontrol2 agentcontrol = (Operator_agentcontrol2)Page.LoadControl("~/operator/agentcontrol2.ascx");
agentcontrol.displayLevel = (int)Common.WinLose_Level.lvChild4 + 10 + (Panel_agents.Controls.Count * 10);
agentcontrol.AppendProcess += Append_UC_Progress;//Error line
the event in the page-
public void Append_UC_Progress(object sender, EventArgs e)
{
Common.WinLose_ProgressStage wps = (Common.WinLose_ProgressStage)e;
progress.AppendProgress(wps);
SaveProgressVS();
}
-USER CONTROL
public partial class Operator_agentcontrol2 : System.Web.UI.UserControl
{
public event EventHandler<Common.WinLose_ProgressStage> AppendProcess;
}
Thanks
---Update---
I have tried to follow https://msdn.microsoft.com/en-us/library/db0etb8x(v=vs.85).aspx for the custom event handler.
but then i got this error
---Update---
Eventually I found that actually my scenario doesn't require to use something like EventHandler
i have changed the code in user control
public partial class Operator_agentcontrol2 : System.Web.UI.UserControl
{
public event EventHandler AppendProcess;
}
By doing this the error is gone, and the user control still able to call the Page's function successfully with an object Common.WinLose_ProgressStage.
As far as I can see, two errors are being reported...
1 - It cannot find a suitable overload for Append_UC_Progess (which takes a Common.WinLose_ProgressStage as an argument)
2 - The assembly containing Common.WinLose_ProgressStage is not referenced.
What I would suggest is happening, is that once it is all compiled the assembly containing Common.WinLose_ProgressStage gets pulled in (perhaps by another referenced assembly), and thus it is noticed that it inherits from EventArgs. It can therefore find a suitable overload of Append_UC_Progess and it all resolves ok.
In order to get rid of the error, I would suggest explicitly referencing the assembly containing Common.WinLose_ProgressStage, so that Visual Studio can see the inheritance tree at design time.
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();
...
}
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.
With the help of fiddler, I did this "replay attack" with the following HTTP GET request
http://svr/Default.aspx?__EVENTTARGET=LinkButton1&__EVENTARGUMENT=&__VIEWSTATE=%2snipg%3D%3D&__EVENTVALIDATION=%2snip
To my surprise, it works as long as there is valid viewstate and event validation. The following stops GET on my click event, but...
protected void BtnUploadClick(object sender, EventArgs e)
{
if(Request.RequestType == "GET") throw new HttpException(405, "GET not allowed for this.");
}
I have events all over my code. Is there a way to globally add this behavior to events that are normally postback events?
You can yes. Attach to application's PreRequestHandlerExecute event. Do it either as a separate HttpModule or in Global.asax.
In event hadler you can either check:
_EVENTTARGET_ , _VIEWSTATE_ are not part of Request.QueryString property (on each request)
on GET you can check that Request.Form is empty. Because asp.net only posts a form on POST actions.
Accepted answer has solved very well the issue for me.
As it only contains some suggestions, I would like to post my own answer with an example of implementation, hoping it will be helpful for somebody (the method name is the one to use for Global.asax, for a httpmodule feel free to adapt) :
public void Application_PreRequestHandlerExecute(Object sender, EventArgs e)
{
// The code below is intended to block incoming HTTP GET requests which contains in query string parameters intended to be used in webform POST
if (Request.HttpMethod != "GET")
{
return; // Nothing to do
}
var hasPostParams = (Request.QueryString["__EVENTTARGET"] ??
Request.QueryString["__VIEWSTATE"] ??
Request.QueryString["__EVENTARGUMENT"] ??
Request.QueryString["__EVENTVALIDATION"]) != null;
if (hasPostParams)
{
// TODO : log error (I suggest to also log HttpContext.Current.Request.RawUrl) and throw new exception
}
}
Assuming you never want to process GETs for this particular application on certain page types you can disable GET for the various pages in your application using IIS. Under the Properties pane for the site or application click on Home Directory and then Configuration (assuming an application is configured) then click on the ASPX or other extension and you can limit the verbs in use for that extension.