1

I'm not sure if this is the correct way to go about the problem I need to solve... however in an OnActionExecuting action filter that I have created, I set a cookie with various values. One of these values is used to determine whether the user is visiting the website for the very first time. If they are a new visitor then I set the ViewBag with some data so that I can display this within my view.

The problem I have is that in some of my controller actions I perform a RedirectToAction. The result is OnActionExecuting is fired twice, once for the original action and then a second time when it fires the new action.

<HttpGet()>
Function Index(ByVal PageID As String) As ActionResult

    Dim wo As WebPage = Nothing

    Try
        wp = WebPages.GetWebPage(PageID)
    Catch sqlex As SqlException
        Throw
    Catch ex As Exception
           Return RedirectToAction("Index", New With {.PageID = "Home"})
       End If
    End Try

    Return View("WebPage", wp)

End Function

This is a typical example. I have a data driven website that gets a webpage from the database based on the PageID specified. If the page cannot be found in the database I redirect the user to the home page.

Is it possible to prevent the double firing in anyway or is there a better way to set a cookie? The action filter is used on multiple controllers.

cw_dev
  • 465
  • 1
  • 12
  • 27
  • I actually decided that an alternative approach was to change my code to OnActionExecuted and then checked to see if the result was a viewresult. E.g. If TypeOf filterContext.Result Is ViewResult Then... This seemed to solve my issue of my code only firing once. – cw_dev Mar 21 '14 at 15:33

4 Answers4

4

Had the same issue. Resolved by overriding property AllowMultiple:

public override bool AllowMultiple { get { return false; } }

public override void OnActionExecuting(HttpActionContext actionContext)
{
    //your logic here
    base.OnActionExecuting(actionContext);
}
Andrey Gubal
  • 3,481
  • 2
  • 18
  • 21
1

You could return the actual action instead of redirecting to the new action. That way, you dont cause an http-request, thereby not triggering the onactionexecuting (i believe)

  • So: Function Index(ByVal PageID As String) As ActionResult Dim wo As WebPage = Nothing Try wp = WebPages.GetWebPage(PageID) Catch sqlex As SqlException Throw Catch ex As Exception Return Index("Home") End If End Try Return View("WebPage", wp) End Function – Dannie Walden Mar 20 '14 at 20:18
  • Thanks, the easier way in this example would be to set wp = WebPages.GetWebPage("Home") and then let is call the view it was supposed to. – cw_dev Mar 21 '14 at 11:12
1

You can save some flag value into TempData collection of controller on first executing and if this value presented, skip filter logic:

if (filterContext.Controller.TempData["MyActionFilterAttribute_OnActionExecuting"] == null)
{
    filterContext.Controller.TempData["MyActionFilterAttribute_OnActionExecuting"] = true;
}
Yuriy Rozhovetskiy
  • 22,270
  • 4
  • 37
  • 68
1

Old question, but I just dealt with this so I thought I'd throw in my answer. After some investigating I disovered this was only happening on endpoints that returned a view (i.e. return View()). The only endpoints that had multiple OnActionExecuting fired were HTML views that were composed of partial views (i.e. return PartialView(...)), so a single request was "executing" multiple times.

I was applying my ActionFilterAttribute globally to all endpoints, which was working correctly on all other endpoints except for the view endpoints I just described. The solution was to create an additional attribute applied conditionally to the partial view endpoints.

// Used specifically to ignore the GlobalFilterAttribute filter on an endpoint
public class IgnoreGlobalFilterAttribute : Attribute {  }

public class GlobalFilterAttribute : ActionFilterAttribute
{
  public override void OnActionExecuting(ActionExecutingContext filterContext)
  {
    // Does not apply to endpoints decorated with Ignore attribute
    if (!filterContext.ActionDescriptor.GetCustomAttributes(typeof(IgnoreGlobalFilterAttribute), false).Any())
    {
      // ... attribute logic here
    }
  }
}

And then on my partial view endpoints

[HttpGet]
[AllowAnonymous]
[IgnoreGlobalFilter] //HERE this keeps the attribute from firing again
public ActionResult GetPartialView()
{
  // partial view logic
  return PartialView();
}
Taylor
  • 176
  • 1
  • 9