Нулевой сеанс в конструкторах контроллера MVC ASP.Net


88

Почему в конструкторах контроллеров Session null? Доступ к нему можно получить из методов действия. Предположительно, поскольку инфраструктура маршрутизации MVC отвечает за создание контроллера, она просто не (повторно) создала экземпляр сеанса в этот момент.

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

[Мне удалось обойти проблему, используя шаблон отложенной загрузки.]

Ответы:


79

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

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

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


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

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

61

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

System.Web.HttpContext.Current.Session

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


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

@BrianCooksey в чем разница?
MichaelMao

1
Controller.Session имеет тип System.Web.HttpSessionStateBase (см. Msdn.microsoft.com/en-us/library/… ), но System.Web.HttpContext.Current.Session имеет тип System.Web.SessionState.HttpSessionState (см. Msdn .microsoft.com / en-us / library /… )
Брайан Кукси,

Старый ответ, но хотел сказать, что System.Web.HttpContext.Current.Sessionэто также есть nullв инстанциаторе VS2019 MVC.
jp2code

11

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


1
Чтобы добавить к Андрею Ринеа, это конкретный пример упомянутой им техники: iridescence.no/post/…
murki

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

8

Вы можете переопределить метод 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)); 
    });
}

2

Этот ответ может быть полезен для некоторых людей

Если мы переопределим метод Initialize, мы должны инициализировать базовый класс контекстом запроса: base.Initialize (requestContext);

protected override void Initialize(RequestContext requestContext)
        {
            base.Initialize(requestContext);
           

        }

Полезно. Обратите внимание, что подпись метода protected override void Initialize(System.Web.Routing.RequestContext requestContext).
Martin_W
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.