cw_dev
cw_dev

Reputation: 465

OnActionExecuting fires multiple times

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.

Upvotes: 1

Views: 6105

Answers (4)

Taylor
Taylor

Reputation: 196

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();
}

Upvotes: 1

Andrey Gubal
Andrey Gubal

Reputation: 3479

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);
}

Upvotes: 4

IUnknown
IUnknown

Reputation: 22448

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;
}

Upvotes: 1

Dannie Walden
Dannie Walden

Reputation: 29

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)

Upvotes: 1

Related Questions