OutputCache and Logging in ASP.NET MVC 2.0 - asp.net-mvc

I think I might already know the answer, but here goes. I want to log when certain methods are called, but I'm torn because I've been gaining performance benefits by using the OutputCache attribute with those methods. When the method is called many times, ASP.NET MVC returns the HTML from prior calls while the cache hasn't expired and it's nice and fast. But any logging commands within that method wouldn't execute.
Is there some way for me to turn on logging to record when those methods are called, without having to remove [OutputCache] and losing the performance benefits I'm getting? Would an attribute-based logging mechanism somehow work even though the [OutputCache] attribute basically short-circuits method execution when prior output has been cached?
Thanks,
Jeff

You could use the Application_BeginRequest and Application_EndRequest events in Global.asax to log information before and after the action is executed. Those events will fire even for controller actions decorated with the [OutputCache] attribute.

Darin Dimitrov is correct, use the Application_BeginRequest and Application_EndRequest methods.
This is how you would do it:
protected void Application_BeginRequest()
{
var routeCollection = RouteTable.Routes;
var routeData = routeCollection.GetRouteData(new HttpContextWrapper(HttpContext.Current));
// Log
Debug.WriteLine("Invoking " + routeData.Values["Controller"] + "::" + routeData.Values["Action"]);
}
protected void Application_EndRequest()
{
// Log
Debug.WriteLine("EndRequest");
}
Those methods will get called regardless if the version is served from the cache or not.

Related

HTTP module vs action filter in asp.net-mvc

I am developing an application in asp.net MVC3 and I have the following questions:
When should I write an HTTP module and when should I write an action filter?
Filter are more MVC approach of doing thing whereas Http Module are more of ASP.NET way of doing thing. Both serve similar purpose by providing hook in the processing pipline.
HttpModule is more generic and when you want some thing to be processed on every request. Filters are useful for adding action specific behaviour.
If you want some thing to be executed only once per Http Request, you should use an HttpModule. ActionFilter may get executed several times during a request until and unless you check IsChildActionOn.
HttpModule are called before and after the request handler executes. They are intended to enable a developer to intercept, participate, or modify each request. There are 22 available events that can be subscribed to that enables the module to work on the request in various stages of the process. The events are useful for page developers who want to run code when key request pipeline events are raised. They are also useful if you are developing a custom module and you want the module to be invoked for all requests to the pipeline.
Filters are designed to inject logic in between MVC request life cycle. Specifically before and after de action is invoked, as well as, before and after the result is processed. Filters provide users with powerful ways to inspect, analyze, capture and instruments several things going around within MVC projects. As of MVC5, there are 5 types of filters :
Authentication
Authorization
Action
Result
Exception
So if you want to intercept, participate, or modify in a specific of the 22 events in the http request pipeline choose the modules. If your logic is is strictly related to the action method you better server overriding one of the following ActionFilterAttribute methods:
OnActionExecuting
OnActionExecutted
OnResultExecuting
OnResultExecuted
HttpModule is how IIS allows an Web application to override the default behavior or add custom logic by letting you attach event handlers to HttpApplication events.
Different IIS modes (Integrated or Classic) even use has different Web.config settings.Reference:
http://msdn.microsoft.com/en-us/library/ms227673(v=vs.100).aspx
Example: redirect non-www to www URLs
public void Init(HttpApplication application)
{
application.PreRequestHandlerExecute += this.Application_PreRequestHandlerExecute;
}
private void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
Uri requestUrl = HttpContext.Current.Request.Url;
string host = requestUrl.Authority.ToLower();
if (!host.StartsWith("www"))
{
HttpContext.Current.Response.Redirect(requestUrl.Scheme + "://www." + host + requestUrl.PathAndQuery);
HttpContext.Current.Response.End();
}
}
An Action Filter is an attribute decorating controllers or action methods. It is an abstraction layer between MVC routing and action methods. With action filters, we can apply same logic to multiple controllers or action methods. for example, custom logging.

How to call a function *only once* in ASP.NET MVC page cycle

I have an ASP.NET MVC web app and have a function that I need to call when the page loads only once. Right now I have the function being called from a base controller OnActionExecuted.
The issue I'm having is that this function is called multiple times - once for the page, and then multiple times for different ajax calls that I have on the page. I've tried putting the function on Controller Initialize but this is also called for each ajax call to a controller action. So is there some function in the ASP.NET MVC page cycle that only gets called when a page is requested (GET) and not for all of the ajax calls (POST)? The only thing I can think of is putting all of the ajax calls in separate controllers that don't inherit from the base controller but there must be a nicer solution.
Depending on how you're doing your AjaxRequests you could use something like the following:
public ActionResult Index()
{
if (!Request.IsAjaxRequest())
{
LoadConfiguration();
}
// Rest of Action method (snip)...
}
This works if, for instance, you're performing Ajax with the jQuery JavaScript library which sends a special token to the server to indicate that it's an Ajax call (I'm sure other libraries do this). This might be better just in case someone changes the JavaScript code to perform GET Ajax requests.
One thing you mentioned does intrigue me though "The issue I'm having is that this function is called multiple times" - actually 'technically' this is not true. It IS only getting called once....per request, all those Ajax calls are treated as separate requests by the server, as if the user is requesting a page via the web browser. It sounds like what you really need is a way to differentiate between web page HTTP Requests, and Ajax HTTP Requests, hence the above solution.
It came to me right after posting the question...
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
base.Initialize(requestContext);
if (Request.HttpMethod == "GET")
{
LoadConfiguration();
}
}
You can either do this work in the application scope (on start, in global.asax or other similar approaches), or store a configuration object in the session (or a flag to identify it has already been done, if there is nothing to store).

ASP.Net MVC Nhibernate Session

When moving to MVC, and now IIS7, we started having issues in that our HTTP Module that opens and closes the ISession was called on every request (static files, etc.). I wanted to avoid doing a full rewrite of NH session management, so I implemented this code in my module, to filter out everything but requests going to the mvchandler:
void context_PreRequestHandlerExecute(object sender, System.EventArgs e)
{
HttpContext context = ((HttpApplication)sender).Context;
Type mvcht = typeof(System.Web.Mvc.MvcHandler);
if (context.Handler != null && context.Handler.GetType().IsAssignableFrom(mvcht))
{
// Code Here
}
}
My question is, I have never used this event in the request pipline. So, are there any hidden pitfalls in doing this? Also, am I looking at a performance issue in running this check for every request? I haven't noticed anything yet, but this is a new and still small app.
Although this doesn't specifically address your question, it should be noted that the cost of opening a session is very minimal. So you may consider not even performing this check in the first place.

Prevent Caching of Attributes in ASP.NET MVC, force Attribute Execution every time an Action is Executed

According to various articles (e.g. here and here) attribute results on ASP.NET MVC Actions may be cached and not executed again when a controller action is called.
That behavior is not desired in my case (e.g. I have an authorization system based on my own attributes and IPs, role checks that need to execute every time, and other things).
How can I prevent ASP.NET MVC from caching my attributes/attribute execution results and guarantee that they are executed every time?
Look at the source code for the AuthorizeAttribute (on Codeplex or via Reflector) to see how it goes about turning off caching for authorized pages. I refactored it into a separate method on my custom authorization attribute which derives from AuthorizeAttribute.
protected void CacheValidateHandler( HttpContext context, object data, ref HttpValidationStatus validationStatus )
{
validationStatus = OnCacheAuthorization( new HttpContextWrapper( context ) );
}
protected void SetCachePolicy( AuthorizationContext filterContext )
{
// ** IMPORTANT **
// Since we're performing authorization at the action level, the authorization code runs
// after the output caching module. In the worst case this could allow an authorized user
// to cause the page to be cached, then an unauthorized user would later be served the
// cached page. We work around this by telling proxies not to cache the sensitive page,
// then we hook our custom authorization code into the caching mechanism so that we have
// the final say on whether a page should be served from the cache.
HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
cachePolicy.SetProxyMaxAge( new TimeSpan( 0 ) );
cachePolicy.AddValidationCallback( CacheValidateHandler, null /* data */);
}
I just finished a spirited discussion with Craig Stuntz (the author of the first article you listed).
I ended up using an AuthorizeAttribute with AuthorizeCore to guarantee that authorization is called even in the event the page is cached.

Controller equivalent of HttpContext.Current in ASP.NET MVC

I'd like to get access to the current executing Controller so I can offload the return of the appropriate ActionResult onto a helper method. To this end, I'm looking for the equivalent of what I would have thought would be ControllerContext.Current but isn't. Thanks!
Edit for clarification: I've got a generic form control which is JavaScript-based but I'd like to add an option so that it works with noscript. At the moment my Controller sets the ViewData.Model to a JSON-ified Models.FormResponse<T>.
This FormReponse is set up with the status of the post and any error messages that were generated, so I'd like a GetActionResult() method which does the script/noscript check (a hidden form input) and either:
Sets the Model to the JSONed FormResponse and returns a View(), or
Serializes the FormResponse to the Session and returns a Redirect().
As this obviously changes the return value and I don't want to do the check myself every time, I need to call View or Redirect from the FormResponse's GetActionResult method in order to call this as:
return formResponse.GetActionResult();
I know with a more astronautical design this could be made even more robust but as the noscript option is not a major feature at the moment, I just need to get a quick solution working that doesn't break other things.
Update #2
The following, implemented in an ActionResult class, does the job for me. Thanks CVertex!
public override void ExecuteResult(ControllerContext context)
{
if (CMSEnvironment.NoScript)
{
Oracle.Response.Redirect(Oracle.Request.UrlReferrer.ToString(), true);
}
context.Controller.ViewData.Model = _model.ToJSON();
new ViewResult()
{
ViewName = Areas.Site.Helpers.SharedView.Service,
ViewData = context.Controller.ViewData
}.ExecuteResult(context);
}
Statics are bad for testability, and very much discouraged in MVC.
Why do you want to access the current controller and action method?
The best way to do this is to implement your own ActionFilter.
This gives you a means of intercepting requests before or after actions methods execute.
EDIT:
By intercepting the result inside OnActionExecuted of a filter, you can do your noscript/script checks and modify your ViewData accordingly for consumption by the View.
Inside OnActionExecuted, you can also do the noscript check and have complete control over the final ActionResult or the ViewData, as you please.
Or, you can write your own ActionResult that makes all these decisions.
So, your controller action ultimately does
return new MyActionResult(format_and_view_agnostic_model_object);
There doesn't appear to be a way to navigate to the current Controller from a thread. That is you could get the ControllerBuilder and you can get the MvcHttpHandler but neither then lets you access the controller instance that the handler is using.

Resources