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.
Related
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
}
I have few custom action filters like
public class CustomFilter:ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//Some task
}
}
public class CustomFilterNew:ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//Some task
}
}
In my action method
[CustomFilter]
[CustomFilterNew]
public ActionResult Index()
{
return View();
}
Lets say CustomFilterNew exactly does opposite of CustomFilter.
In such case how to prevent one filter action from executing another filter action lets say CustomFilterNew should prohibit executing CustomFilter
Setting the filterContext.Result property to any non-null value will stop execution of later filters. So if your first filter sets filterContext.Result = new RedirectResult(...), the second filter and action method will never be run.
There are many ways to do that as follow
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.Result = new RedirectResult("~/Home/Index");
}
OR
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//Check your condition here
if (true)
{
//Create your result
filterContext.Result = new EmptyResult();
}
else
base.OnActionExecuting(filterContext);
}
OR
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
...
if (needToRedirect) //your condition here
{
...
filterContext.Result = new RedirectToAction(string action, string controller)
return;
}
...
}
Another thing here i have to mentioned how to set Order of filter works you can give an Order to Action Filters as follow to execute filters in order
[FilterOne(Order = 1), FilterTwo(Order = 2)]
Here is a sample action filter. We know that when we write an action filter then we need to decorate the controller with an attribute like this, to use it for any controller.
I like to know whether there is any way to write an action filter which will work for all controllers in way that I do not need to decorate all the controllers with an action filter attribute. Any ideas?
[LogActionFilter]
public class HomeController : Controller
{}
public class LogActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
Log("OnActionExecuting", filterContext.RouteData);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
Log("OnActionExecuted", filterContext.RouteData);
}
private void Log(string methodName, RouteData routeData)
{
var controllerName = routeData.Values["controller"];
var actionName = routeData.Values["action"];
var message = String.Format("{0} controller:{1} action:{2}", methodName, controllerName, actionName);
Debug.WriteLine(message, "Action Filter Log");
}
}
public class LogActionFilterAttribute : IActionFilter
{
public void OnActionExecuted(ActionExecutedContext filterContext)
{
Log("OnActionExecuted", filterContext.RouteData);
}
public void OnActionExecuting(ActionExecutingContext filterContext)
{
Log("OnActionExecuting", filterContext.RouteData);
}
private void Log(string methodName, RouteData routeData)
{
var controllerName = routeData.Values["controller"];
var actionName = routeData.Values["action"];
var message = String.Format("{0} controller:{1} action:{2}", methodName, controllerName, actionName);
Debug.WriteLine(message, "Action Filter Log");
}
}
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalFilters.Filters.Add(new LogActionFilterAttribute());
}
}
For your scenario you can just make a Custom BaseController and put your [LogActionFilter] attribute on Custom Basecontroller and inherit all your Controllers from Custom Basecontroller as shown below :
[LogActionFilter]
public class MyBaseController : Controller
{
}
public class MyOtherController : MyBaseController //<----instead of using Controller as base use MyBaseController as base class
{
public ActionResult Index()
{
// ...
}
}
The advantage of this approach is that you have to put your custom [LogActionFilter] attribute only at one place i.e. only on Custom BaseController.
If you're already subclassing from a base controller, you don't need a filter attribute or to register anything. You can just override the desired methods, e.g.,
public class BaseController : Controller {
protected override void OnActionExecuting(ActionExecutingContext filterContext) {
ViewBag.SomeValue = "glorp frob blizz nunk";
// Access the controller, parameters, querystring, etc. from the filterContext
base.OnActionExecuting(filterContext);
}
}
Then, every controller that subclasses from it will run that method:
public sealed class GlorpController : BaseController {
public ActionResult Index() => View();
}
The view will quite happily see the ViewBag.SomeValue value.
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 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.