I created an attribute class, here is the code
namespace ZDemo.Validate1
{
public class ValidateRequest : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
/*further code*/
}
base.OnActionExecuting(filterContext);
}
}
}
And added it as an attribute to some actions in different controllers
[Validate1.ValidateRequest]
public ActionResult Add()
{
return View();
}
But when I run this code with a debugger it is not being called at all.
What am I doing wrong?
Call base.OnActionExecuting(filterContext); at the beginning of the method:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
//Your code here
}
Related
I have the following action method:
public class HomeController : Controller
{
[ProfileAction]
[CustomAction]
public string FilterTest()
{
//Does not get executed
return "This is the FilterTest action";
}
}
Here's the code for the filters:
public class CustomActionAttribute : FilterAttribute, IActionFilter
{
public void OnActionExecuting(ActionExecutingContext filterContext)
{
//This is executed first
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
//This is executed third
}
}
public class ProfileActionAttribute : FilterAttribute, IActionFilter
{
public void OnActionExecuting(ActionExecutingContext filterContext)
{
//This is executed second
filterContext.Result = new HttpNotFoundResult();
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
//this does not execute
}
}
According to Microsoft the OnActionExecuted() is executed after a controller action is executed.
The action method FilterTest() is never called because I set the Result property in ProfileActionAttribute.OnActionExecuting().
Why does CustomActionAttribute.OnActionExecuted() get called if the action method never even gets called?
i have ActionFilterAttribute like the following
class MyCustomRouteConstraint : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (something == 1) //i know there is no something variable
{
// do something
}
base.OnActionExecuting(filterContext);
}
}
as you can see in my code there is no variable named as something.
but i want to use the variable named as something in my action.
public ActionResult Index()
{
int something = 1;
return View();
}
public ActionResult About()
{
int something = 2;
return View();
}
public ActionResult Contact()
{
int something = 1;
return View();
}
I think what you need is OnActionExecuted. I have not tested.
class MyCustomRouteConstraint : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var something = Convert.ToInt32(filterContext.RouteData.Values["something"]);
if(something == 1)
{
//do something
}
base.OnActionExecuting(filterContext);
}
}
OnActionExecuting is called by the ASP.NET MVC framework BEFORE the action method executes. So it doesn't make sense to initialize your something variable in the action body. But still if you are going to override some method which is called AFTER the action method executes you can probably use ViewBag to init the variable in the controller and then get its value using filterContext.
You use ViewBag for this as well.
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.Controller.ViewBag.SommeVariable = "Test";
}
And in your action
public ActionResult Index()
{
var variable = ViewBag.SommeVariable;
return View();
}
I use structuremap dependency injection to do that. See here some snippets:
namespace something.Infrastructure.ActionFilters {
public class PlatformAuthorizeAttribute : AuthorizeAttribute
{
public IRepository<User> UserRepo { get; set; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
if (WebSecurity.Initialized && filterContext.HttpContext.User.Identity.IsAuthenticated)
{
if (filterContext.HttpContext.User.IsInRole("Banned"))
{
WebSecurity.Logout();
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary
{
{"Controller", "Home"},
{"Action", "Banned"},
{"Area", ""}
});
}
UserRepo.Dispose();
UserRepo = null;
}
}
}
}
And then initialize the following mapping in your IoC structuremap class:
public static class IoC
{
public static IContainer Initialize()
{
ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
});
x.SetAllProperties(pset =>
{
pset.WithAnyTypeFromNamespace("something.Infrastructure.ActionFilters");
pset.OfType<IRepository<User>>();
});
});
return ObjectFactory.Container;
}
}
I think this is the cleanest way to provide your action filters with properties. Note that in my example I used a custom AuthorizeAttribute. You will need to change this to ActionFilterAttribute and use the OnActionExecuting method override to access the properties.
Use HttpContext.Items
HttpContext.Items["something"] = 1;
In ActionFilter, you can access it as:
var something = (int)filterContext.HttpContext.Items["something"];
However, your example of action filter is OnActionExecuting; this will execute before any of your Index/About actions executes. So you should initialize 'something' somewhere else as per your needs (for example, inside controller's OnActionExecuting method).
I'm trying to change the method OnAuthorization, so that it is available for any application ... this way:
public partial class Controller
{
protected override void OnAuthorization(AuthorizationContext filterContext)
{
if ((string)(filterContext.RouteData.Values["action"]) == "test")
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
}
but is showing the compilation error:
Controller.OnAuthorization(System.Web.Mvc.AuthorizationContext)': no
suitable method found to override
Can someone help me?
You have to create you own base controller class:
public partial class BaseController : Controller
{
protected override void OnAuthorization(AuthorizationContext filterContext)
{
if ((string)(filterContext.RouteData.Values["action"]) == "test")
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
}
Use BaseController in your code.
And remember that filterContext.RouteData.Values["action"] can be Test or TEST or tEST.
I have a BaseController in which I put in some data in the ViewData collection by overriding OnActionExecuting.
Now i have an Action in a ChildController that doesn't need that view data.
For that purpose I created an DontPopulateViewData ActionFilterAttribute that sets a bool on the BaseController that prevents the BaseController from populating the viewdata.
Problem: the ActionFilters OnActionExecuting method is called after the one in BaseController and not before.
Will ActionFilters always be called before overridden OnActionExecuting in base controllers and is there a way to get around this?
In addition to what Marwan Aouida posted and suggested (using an ActionFilter on the base class), I don't think you're going to be able to create an ActionFilter that executes before the OnActionExecuting() overload on the base class. The following code:
[MyActionFilter(Name = "Base", Order = 2)]
public class MyBaseController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
Response.Write("MyBaseController::OnActionExecuting()<br>");
base.OnActionExecuting(filterContext);
}
protected override void Execute(System.Web.Routing.RequestContext requestContext)
{
requestContext.HttpContext.Response.Write("MyBaseController::Execute()<br>");
base.Execute(requestContext);
}
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
Response.Write("MyBaseController::OnActionExecuted()<br>");
base.OnActionExecuted(filterContext);
}
}
public class MyActionFilter : ActionFilterAttribute
{
public string Name;
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
filterContext.HttpContext.Response.Write("MyActionFilter_" + Name + "::OnActionExecuted()<br>");
base.OnActionExecuted(filterContext);
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.HttpContext.Response.Write("MyActionFilter_" + Name + "::OnActionExecuting()<br>");
base.OnActionExecuting(filterContext);
}
}
public class MyTestController : MyBaseController
{
[MyActionFilter(Name = "Derived", Order = 1)]
public void Index()
{
Response.Write("MyTestController::Index()<br>");
}
}
produces this output:
MyBaseController::Execute()
MyBaseController::OnActionExecuting()
MyActionFilter_Derived::OnActionExecuting()
MyActionFilter_Base::OnActionExecuting()
MyTestController::Index()
MyActionFilter_Base::OnActionExecuted()
MyActionFilter_Derived::OnActionExecuted()
MyBaseController::OnActionExecuted()
The ActionFilterAttribute class has a property called "Order" which you can use to set the order in which the Action Filters are executed.
In your case you have to set the order of the Filter Attribute in the BaseController to 2 and the Filter Attribute in the DerivedController to 1:
[MyFilter(Order=2)]
public class BaseController:Controller
{
public ActionResult MyAction() {
}
}
[MySecondFilter(Order=1)]
public class DerivedController:BaseController
{
public ActionResult AnotherAction() {
}
}
Read this for more infos: http://msdn.microsoft.com/en-us/library/dd381609.aspx
Note: I didn't test this.
If you have a model-bound parameter in an action method, how can you get to that parameter in an action filter?
[MyActionFilter]
public ActionResult Edit(Car myCar)
{
...
}
public class MyActionFilterAttribute : ActionFilterAttribute
{
public void OnActionExecuted(ActionExecutedContext filterContext)
{
//I want to access myCar here
}
}
Is there anyway to get myCar without going through the Form variables?
Not sure about OnActionExecuted but you can do it in OnActionExecuting:
public class MyActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// I want to access myCar here
if(filterContext.ActionParameters.ContainsKey("myCar"))
{
var myCar = filterContext.ActionParameters["myCar"] as Car;
if(myCar != null)
{
// You can access myCar here
}
}
}
}