Is there any way to find out on client side what kind of action was executed? I just want to know if view is generated by PartialView method or View method.
I looked in headers but found nothing useful.
To achieve this I may add some headers into http response by overriding PartialView method.
protected override PartialViewResult PartialView(string viewName, object model)
{
Response.AddHeader("is-partial", "of_course_this_is_partial");
return base.PartialView(viewName, model);
}
But I want to know is there any built in solution in MVC 5? So I won't have to use a custom derived Controller class and use it everywhere.
You could use an action filter:
public class ResponseHeaderActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
// use filterContext.Result to see whether it's a partial or not
// filterContext.HttpContext.Response.AddHeader()..
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
}
}
If you make this a global action filter, it's automatically executed and you don't have to inherit from a base controller or put it as an attribute on your controller:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
// Register global filter
GlobalFilters.Filters.Add(new ResponseHeaderActionFilter());
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
This way, the header is automatically added to each result.
Related
I have a scenario i need to check security for each menu item if user 'A' is allowed to access this menu or not and for that reason i created a class which is inherited with ActionFilterAttribute
public class SecurityFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
Log("OnActionExecuting", filterContext.RouteData);
}
}
and using this class on my controller
[SecurityFilter]
public class XYZController : Controller
{
public ActionResult Index() {
return View();
}
}
Now the problem is in my View i have #Html.Action() calls e.g
#Html.Action("COM")
which results in calling onActionExecuting Method again, i Just want it to call it one time when menu link is clicked and for that method only where menu is redirecting not the other Action method which is render inside view
When called using #Html.Action the IsChildAction property of the filterContext will be true. You can rely on it to determine whether you actually want to do something or not:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.IsChildAction)
return;
Log("OnActionExecuting", filterContext.RouteData);
}
See MSDN
I would like to protect my public method from being called by a user.
Because I'm calling the action from an ajax script I can't use any access modifiers, (private, protected etc).
Also, [HttpPost] doesn't stop the user from doing a fake request.
Anyone got a solution?
Thanks
Create an action filter that allows action methods to be called by AJAX only
namespace MyFilters
{
[AttributeUsage(AttributeTargets.Method)]
public class AjaxOnlyAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.HttpContext.Response.StatusCode = 404;
filterContext.Result = new HttpNotFoundResult();
}
else
{
base.OnActionExecuting(filterContext);
}
}
}
}
Then apply this to the action method
[AjaxOnly]
public JsonResult DoSomething()
{
....
In order to disable browser cache, to reliably instructing the browser not to cache, I found the best solution was to create your own [NoCache] attribute class
public class NoCacheSettingsAttribute : ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
filterContext.HttpContext.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
filterContext.HttpContext.Response.Cache.SetValidUntilExpires(false);
filterContext.HttpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
filterContext.HttpContext.Response.Cache.SetNoStore();
base.OnResultExecuting(filterContext);
}
}
And a global filter settings
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
// Makes sure that cached pages are not served to any browser including chrome
filters.Add(new NoCacheSettingsAttribute());
}
I want to use [OutputCache(CacheProfile = "2Hour")] in some ActionResult of a controller and also want to use NoCacheSetting for rest of controller globally , Let say in BaseController, (all controller inherit from BaseController)
So the question is that will it work properly ? Or I have to put rest of controller 1 by one ?
Why not simply exclude controller actions already decorated with the OutputCache attribute from processing:
public class NoCacheSettingsAttribute : ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
var descriptor = new ReflectedControllerDescriptor(
filterContext.Controller.GetType()
);
var action = descriptor.FindAction(
filterContext.Controller.ControllerContext,
filterContext.RequestContext.RouteData.GetRequiredString("action")
);
if (!action.GetCustomAttributes(typeof(OutputCacheAttribute), true).Any())
{
// The controller action is not decorated with the
// [OutputCache] attribute, so you could apply your NoCache logic here
filterContext.HttpContext.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
filterContext.HttpContext.Response.Cache.SetValidUntilExpires(false);
filterContext.HttpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
filterContext.HttpContext.Response.Cache.SetNoStore();
}
}
}
The code:
public class TheFilter : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
}
}
public class NotesController : BaseController
{
[TheFilter]
[HttpPost]
public ActionResult Edit(EditViewModel viewModel)
{
viewModel.Note.Modified = DateTime.Now;
viewModel.Note.ModifiedBy = User.Identity.Name;
var noteTable = StorageHelper.GetTable<Note>(viewModel.PageMeta.DataSourceID);
noteTable.AddOrUpdate(viewModel.Note);
return Home();
}
}
When I debug on return Home() and step through then I bypass the action filter and go straight to the Home() method.
Am I declaring the action filter correctly?
Make sure you're implementing
System.Web.Mvc.ActionFilterAttribute
and not
System.Web.Http.Filters.ActionFilterAttribute
They both have OnActionExecuting and OnActionExecuted Methods, so it can be a little deceiving.
Maybe you don't reach the method directly but call Edit action from other action?
put the filter on the controller and see what happens.
I was also facing the same issue I was just missing the override keyword before the OnExecuting method. It started working after adding override keyword.
Use the Onexecuting not onExecuted
public override void OnActionExecuting(ActionExecutingContext filterContext)
[ApiBasicAuthorize]
public ActionResult SignIn()
{
}
I have this custom filter called ApiBasicAuthorize. Is it possible to access ApiBasicAuthorize's data (properties etc) inside the controller action SignIn?
If not, how do I pass data from the filter to controller action?
There is a dictionary called items attached to the HttpContext object. Use this dictionary to store items shared across components during a request.
public override void OnAuthorization(AuthorizationContext filterContext)
{
filterContext.HttpContext.Items["key"] = "Save it for later";
base.OnAuthorization(filterContext);
}
Then anywhere in your code later in the request...
var value = HttpContext.Current.Items["key"];
public override void OnAuthorization(AuthorizationContext filterContext)
{
var rd = filterContext.RouteData;
//add data to route
rd.Values["key"]="Hello";
base.OnAuthorization(filterContext);
}
public ActionResult(string key)
{
//key= Hello
return View();
}