Перенаправление с инициализации контроллера не работает

У меня есть переопределение для контроллера, который проверяет, существуют ли определенные данные сеанса. Эти данные необходимы для правильной работы репозитория, поэтому, если они не существуют, после проверки пользователь должен выйти из системы.

protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
    base.Initialize(requestContext);
    if (Session["CompanyID"] != null)
    {
        repo.CompanyID = (long)Session["CompanyID"];
    }
    else
    {
        RedirectToAction("LogOff", "Account");
    }
}

Мой код выглядит так, но даже когда вызывается RedirectToAction, контроллер по-прежнему открывает действие по умолчанию, и пользователь не выходит из системы. Можете ли вы порекомендовать, как справиться с этой проблемой?

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

Эти данные являются частью пользователя в базе данных. Я создал пользовательское членство и поставщик ролей. Есть ли способ каким-то образом добавить эти данные в «Пользователь» типа MembershipUser, чтобы к ним можно было получить доступ в конструкторе, например, к имени пользователя?




Ответы (2)


Вместо этого рассмотрите возможность использования пользовательского ActionFilter.

public class HasCompanyIdAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.HttpContext.Session["CompanyID"] == null)
        {
            filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new {action = "LogOff", controller = "Account"}));
        }
    }
}

Затем его можно применить так:

[HasCompanyId]
public class MyController : Controller 
{
    public ActionResult SomeAction()
    {
        return View();
    }
}

Это применит атрибут ко всем запросам, которые обрабатывает MyController (или его подклассы).

person Rich O'Kelly    schedule 22.11.2011
comment
Я понимаю принцип, но он кажется немного непрактичным. Я не могу сделать его глобальным фильтром, так как есть общедоступные области приложения, и тогда я должен применять его к каждому действию, которое находится внутри области, которая требует этого? Есть ли другой способ прервать загрузку контроллера после инициализации и отправить его другому действию другого контроллера? - person Zaak; 22.11.2011
comment
Вы можете применить атрибут к контроллеру, и он будет применяться для каждого действия внутри этого контроллера или базового класса контроллера, а затем действие будет применяться и для каждого действия производного класса! - person Rich O'Kelly; 22.11.2011
comment
Хм, этот способ все еще не учитывает тот факт, что я должен установить его один раз. Кажется, что выполнение действий через FilterAttribute таким образом будет устанавливать его каждый раз, когда действие выполняется, а не только при создании экземпляра контроллера? - person Zaak; 22.11.2011
comment
См. обновление для того, как его можно применить. Да, вам нужно будет выполнять проверку каждый раз, когда выполняется один из методов действия контроллера, поскольку время жизни контроллера обычно не привязано к сеансу. - person Rich O'Kelly; 22.11.2011
comment
Я понял, что вы имели в виду. Я знал, как использовать фильтр на контроллере. Моя проблема заключалась в назначении CompanyID каждый раз, когда применялся фильтр, но потом я понял, что могу сохранить текущий способ его назначения и использовать фильтр только для проверки SessionAlive. спасибо, это очень помогло. - person Zaak; 22.11.2011

Просто реализуйте свое решение, переопределив OnActionExcuting в базовом классе. Затем вы можете делать все, что вы можете делать в фильтре действий. Вот так:

public void OnActionExecuting(ActionExecutingContext filterContext){
  if (filterContext.HttpContext.Session["CompanyID"] != null)
     repo.CompanyID = (long)filterContext.HttpContext.Session["CompanyID"];
  else
     filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new {action = "LogOff", controller = "Account"}));
}

Некоторый код опущен для краткости.

Я попробовал оба подхода и обнаружил, что реализовать его с помощью фильтра действий было сложнее из-за требований к внедрению зависимостей, которые у меня были. Вы можете сделать это любым способом, но считаете, что подход базового класса был немного яснее. Я также хотел установить некоторые свойства базового класса, чтобы сделать несколько стандартных объектов доступными для методов контроллера, чтобы сохранить повторяющийся код, который разработчики добавляли к действиям. Подход базового класса упростил эту задачу.

Я добавлю одно предостережение: я не утверждаю, что это хороший подход к аутентификации/безопасности, я смотрю на это исключительно с точки зрения желания выполнить некоторые операции/проверку до выполнения действия, а также настроить некоторые предварительно заполненные данные об экземпляре контроллера, чтобы следовать принципу DRY.

Надеюсь, поможет.

person tidmutt    schedule 03.02.2012