So I've come to understand that MVC doesn't really have a forms PageLoadevent equivalency so where do I put a code that I would like to execute every time a page loads? I'd like to check for a cookie.
Put it in the Constructor of the MVC Controller.
Or like this:
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
// check for cookies!
}
I think this might fire for every action on the page if there are multiple actions on the page (for example partial views).
If you only want it to fire once you many need to check for
filterContext.IsChildAction
Like this
protected override void OnActionExecuting(ActionExecutingContext filterContext) {
if (filterContext.IsChildAction) return;
// check for cookies!
}
Mentioned here
In ASP.NET MVC 3, what is filterContext.IsChildAction?
Related
We have some obsolete views in our MVC 4 web project. I would like to create some statistic on how often are view files accessed, if at all. If some files are not accessed in a long time, it's possible they are obsolete.
Is it possible to get this information from IIS or windows logs?
You can use filter context before and after action finished execution
to log which view is accesss you can use following example
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
string actionName = filterContext.ActionDescriptor.ActionName;
string controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName
.....
base.OnActionExecuting(filterContext);
}
form the controller and actionname you can maintain your view log's
i hope it help's you..
I'm currently revamping my application. I have a method called "Test" in my controller which is being currently being called my many pages. I've now created a new method called "TestNew" in my controller and I want few of my pages to be redirected to the new method.
It would be great if you can let me know of a quick fix that can be done at one place so that by putting some condition like
if(viewName = "abc")
then redirect to "TestNew", instead of making change across the application. I've tried doing something in
public override void OnActionExecuting(ActionExecutingContext filterContext)
but this never gets called.
Thanks in advance.
This should be really simple as per all ASP MVC books & basics:
public ActionResult Test()
{
return RedirectToAction("NewTest");
}
Hope this helps
I want to keep a log of all the requests to my MVC 3 app, including requested URL, user's ip adress, user agent, etc. Where is the best place to do this,
1) use a base controller?
2) use an action filter?
3) others?
I do this inside my BaseController. Something like this:
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
// If in Debug mode...
if (filterContext.HttpContext.IsDebuggingEnabled)
{
var message = string.Format(CultureInfo.InvariantCulture,
"Leaving {0}.{1} => {2}",
filterContext.Controller.GetType().Name,
filterContext.ActionDescriptor.ActionName.Trim(),
filterContext.Result);
Logger.Debug(message);
}
// Logs error no matter what
if (filterContext.Exception != null)
{
var message = string.Format(CultureInfo.InvariantCulture,
"Exception occured {0}.{1} => {2}",
filterContext.Controller.GetType().Name,
filterContext.ActionDescriptor.ActionName.Trim(),
filterContext.Exception.Message);
Logger.Error(message);
}
base.OnActionExecuted(filterContext);
}
Hope you get the idea.
You can also log before the action is executed using:
protected override void OnActionExecuting(ActionExecutingContext filterContext)
An HttpModule seems like the best fit, if you ask me.
All of the data you're talking about logging is available well before any particular Controller gets invoked. So if you do logging outside of the controller, then you get to capture even those requests which are not to valid controller actions. And there's no need to clutter your controller code with something that's really a cross-cutting concern.
You can have multiple action methods triggered when rendering a single request. Consider using RenderAction on your layout page as follows:
Html.RenderAction("Navigation", "Menu")
It's worth noting that you'd then have two log entries with the same information if you choose to use action filter for logging.
some of my controller actions require a user to be authenticated. Those actions are flagged with a custom [Authorize] attribute. Behind the scene, a custom membership provider does some magic, among which setting some temporary data into the common-thread.
At the end of each action that required an authentication, a call to the OnActionExecuted() filter is required to cleanup the thread. This is done via another custom attribute called [CleanupContext].
So my actions look like this:
[Authorize]
[CleanupContext]
public ViewResult Action()
{
...
}
Since those two are always used together, since I am lazy and since I fear that someday one dev might forget to put one or the other and we end up with some weird behavior: is there a way to combine them into one attribute?
[AuthorizeAndCleanup]
public ViewResult Action()
{
// Aaah, if only it could look like this :D
}
Thanks a lot!
You could derive from AuthorizeAttribute in order to do your custom authorization stuff and implement IActionFilter in order to have access to the OnActionExecuting and OnActionExecuted events (to do your custom cleanup code):
public class AuthorizeAndCleanupAttribute : AuthorizeAttribute, IActionFilter
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
// TODO: your custom authorization logic
return base.AuthorizeCore(httpContext);
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
// TODO: your custom cleanup code
}
public void OnActionExecuting(ActionExecutingContext filterContext)
{
}
}
Obviously you should be aware that neither the OnActionExecuting or the OnActionExecuted events will ever be executed if the authorization fails (a.k.a. the AuthorizeCore method returns false) so make sure you do your cleanup in this method if you are about to return false.
A quick. dirty and (possibly) slow solution that I can think of is to skip the cleanup attribute and check for the presence of the custom Authorize attribute in the OnActionExecuted() and execute any cleanup code if you find it (since you stated that they are always present together).
You should implement your own filter provider (http://bradwilson.typepad.com/blog/2010/07/service-location-pt4-filters.html) which will automatically add Cleanup attribute to any action marked by Authorize.
How can I ensure that information isn't returned from a webmethod or mvc action by just anyone calling it from Jquery/Ajax call/HTTP post get (you get the idea).
Previously I would have used session variables or the view state to do this on every call, is this still possible. Can anyone point me to any good demos around making these calls secure, I've seen a few but they are easy to spoof or work around.
Thanks!
You can use the AuthorizeAttribute as an action filter to filter access to your controllers. You can just add this attribute to the controllers you want to limit the access to. I think the msdn has a good example for this:
http://msdn.microsoft.com/en-us/library/dd381413(v=vs.90).aspx
You can also use Session in this case.
1. create a ActionFilterAttribute class named, e.g., LoginFilterAttribute.
public sealed class LoginFilterAttribute:ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//check if the user is logged in
if (Session["UserSessionKey"]==null)
//redirect to login page or do nothing
else
//return data or do something else
}
}
2. in your action, put this attribute before the action method
[LoginFilter]
public ActionResult ActionNeedLogin()
{
return View();
}
or, register the attribute in global.asax to keep all action from anonymouse access.
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new MyHandleErrorAttribute());
filters.Add(new LoginFilterAttribute());
}