2009-05-20 5 views
80

Почему Session null в конструкторах контроллеров? Доступ к нему возможен из методов Action. Предположительно, поскольку инфраструктура MVC Routing отвечает за создание контроллера, он просто не восстановил сеанс в этой точке.Сессия null в конструкторах диспетчера ASP.NET MVC

Кто-нибудь знает, если это по дизайну, и если да, то почему?

[мне удалось обойти эту проблему с помощью отложенной загрузки Pattern.]

ответ

68

Андрей прав - это нулевое значение, потому что при работе в рамках структуры ASP.NET MVC HttpContext (и, следовательно, HttpContext.Session) не задан, когда класс контроллера выполнен так, как вы могли ожидать, но он установил (" впрыскивается ") позже классом ControllerBuilder. Если вы хотите лучше понять жизненный цикл, вы можете либо вытащить структуру ASP.NET MVC (источник доступен), либо обратиться к: this page

Если вам нужно получить доступ к сеансу, то одним из способов было бы переопределить метод «OnActionExecuting» и получить к нему доступ, так как он будет доступен к этому времени.

Однако, как указывает Андрей, если ваш код зависит от сеанса, тогда потенциально может быть трудно написать модульные тесты, поэтому, возможно, вы можете рассмотреть возможность переноса сеанса в вспомогательный класс, который затем может быть заменен на другой, не-веб-версии при работе в модульных тестах, поэтому отключает ваш контроллер от сети.

+1

Я не уверен, что это правильное утверждение о HttpContext. Он фактически построен прямо в начале всего потока. Вы можете немного прочитать подробный поток здесь: http://www.beletsky.net/2011/06/inside-aspnet-mvc-route-to-mvchanlder.html , или вы можете использовать отражатель и найти себя при создании httpContext - вокруг строки 1556 в httpruntime.cs. –

+0

@AlexeyShcherbak Он может быть сконструирован уже - OP о том, было ли установлено в свойстве Session контроллера MVC. то есть публичный сеанс HttpSessionStateBase {get; } в System.Web.Mvc.Controller Это разные вещи. – MemeDeveloper

10

Сессия вводится позже в жизненном цикле. Зачем вам нужен сеанс в конструкторе? Если вам это нужно для TDD, вы должны перенести сеанс в макетируемый объект.

+1

Чтобы добавить к Андрею Rinea, это конкретный пример методики, упомянутой им : http://iridescence.no/post/Using-Unit-Tests-to-Uncover-Design-Flaws.aspx – murki

+4

Я хочу получить доступ к сеансу во время моих конструкторов, чтобы иметь доступ к ранее сохраненной информации о сеансе. Да, я мог бы переопределить метод OnActionExecuting, но это, конечно, не изящное решение. –

+0

@ Крис Арнольд, см. Мой ответ. –

50

В дополнение к другим ответам здесь, в то время как Controller.Session не заполняется в конструкторе, вы можете получить доступ к сессии через:

System.Web.HttpContext.Current.Session

со стандартной оговоркой, что это потенциально снижает тестируемость вашего контроллера.

+3

Тип для каждого из этих двух свойств сеанса отличается, что может иметь значение, если вы намерены сохранить ссылку на состояние сеанса. – BrianCooksey

+0

@BrianCooksey Что нового? – MichaelMao

+1

Controller.Session имеет тип System.Web.HttpSessionStateBase (см. Https://msdn.microsoft.com/en-us/library/system.web.mvc.controller.session(v=vs.118).aspx), но System.Web.HttpContext.Current.Session имеет тип System.Web.SessionState.HttpSessionState (см. Https://msdn.microsoft.com/en-us/library/system.web.httpcontext.session(v=vs.110) .aspx) – BrianCooksey

6

Вы можете переопределить метод Initialize для установки сеанса.

protected override void Initialize(RequestContext requestContext) 
2

Если вы используете IoC контейнер, попробуйте инъекционного и используя HttpSessionStateBase вместо Session объекта:

private static Container defaultContainer() 
{ 
    return new Container(ioc => 
    { 
        // session manager setup 
        ioc.For<HttpSessionStateBase>() 
           .Use(ctx => new HttpSessionStateWrapper(HttpContext.Current.Session)); 
    }); 
} 
Смежные вопросы