OnActionExecuting запускает несколько раз

Я не уверен, что это правильный путь решения проблемы, которую мне нужно решить... однако в фильтре действий OnActionExecuting, который я создал, я установил cookie с различными значениями. Одно из этих значений используется, чтобы определить, посещает ли пользователь веб-сайт в первый раз. Если они - новый посетитель, тогда я устанавливаю ViewBag с некоторыми данными, чтобы я мог отобразить это в моем представлении.

У меня проблема в том, что в некоторых из моих действий контроллера я выполняю RedirectToAction. В результате OnActionExecuting запускается дважды: один раз для исходного действия, а затем второй раз, когда запускается новое действие.

<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

Это типичный пример. У меня есть управляемый данными веб-сайт, который получает веб-страницу из базы данных на основе указанного PageID. Если страница не может быть найдена в базе данных, я перенаправляю пользователя на домашнюю страницу.

Можно ли в любом случае предотвратить двойное срабатывание или есть лучший способ установить cookie? Фильтр действий используется на нескольких контроллерах.

3 ответа

Решение

Вы можете сохранить некоторое значение флага в TempData сбор контроллера при первом выполнении и, если это значение представлено, пропустить логику фильтра:

if (filterContext.Controller.TempData["MyActionFilterAttribute_OnActionExecuting"] == null)
{
    filterContext.Controller.TempData["MyActionFilterAttribute_OnActionExecuting"] = true;
}

Была такая же проблема. Разрешается переопределением свойства AllowMultiple:

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

public override void OnActionExecuting(HttpActionContext actionContext)
{
    //your logic here
    base.OnActionExecuting(actionContext);
}

Вы можете вернуть фактическое действие вместо перенаправления на новое действие. Таким образом, вы не вызываете http-запрос, тем самым не вызывая onactionexecuting (я считаю)

Старый вопрос, но я только что разобрался с этим, поэтому подумал, что добавлю свой ответ. После некоторого расследования я обнаружил, что это происходило только на конечных точках, которые возвращали представление (т.е. return View()). Единственные конечные точки, которые имели несколько OnActionExecuting были запущены HTML-представления, состоящие из частичных представлений (т.е. return PartialView(...)), поэтому один запрос "выполнялся" несколько раз.

Я применял свой ActionFilterAttribute глобально ко всем конечным точкам, который корректно работал на всех других конечных точках, за исключением оконечных точек представления, которые я только что описал. Решение состояло в том, чтобы создать дополнительный атрибут, условно примененный к конечным точкам частичного представления.

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

А потом на моем частичном представлении конечных точек

[HttpGet]
[AllowAnonymous]
[IgnoreGlobalFilter] //HERE this keeps the attribute from firing again
public ActionResult GetPartialView()
{
  // partial view logic
  return PartialView();
}
Другие вопросы по тегам