Как получить хранящееся значение в сессии ASP.NET MVC 4?
В одном из методов контроллера устанавливаю значение сессии:
Session["User.Project"] = "Привет";
В другом методе контроллера пытаюсь получить значение:
string test = Session["User.Project"];
В переменную test попадает null. Пробовал HttpContext.Session тоже самое.
Конечно пользователь сначала проходит по первому методу контроллера, потом по второму методу.
Если достать значение сессии в первом методе контролера, сразу после записи то значение там есть. Работает нормально. Но вот во втором методе контроллера его как будто нет.
Александр: Так я его и использую. Visual Studio подсвечивает ошибку в которой написано не HttpContext, который указан у меня, а HttpContextBase (видимо класс на него ссылается).
Quber: по снимку, все нормально, так и должно быть. В контроллере доступ без Current, или вообще можно опустить HttpContext.
По вопросу, почему null - может напутали чего. Например, на снимке имя параметра сессии User_Project, а в тексте вопроса: User.Project. И тип данных разный.
Если нет, то поведение Session вы намерено не настраивали? Cookies у клиента нормально работают? Ну и глупый вопрос, вы уверены, что между переходом от метода, в котором создается сессия, к следующему методу проект не перекомпилируется? :-)
Еще один вопрос, если сессия возвращает тип object, то почему вы пишите string test = Session["User.Project"]; Действительно такой код используете, или это просто ошибка в тексте вопроса?
Например, на снимке имя параметра сессии User_Project, а в тексте вопроса: User.Project. И тип данных разный.
Вариант с нижним дефисом я применил после точки, чтобы исключить её вину (увидел пример выше, где используется нижний дефис).
Если нет, то поведение Session вы намерено не настраивали? Cookies у клиента нормально работают?
Нет, не настраивал. Куки работают нормально.
Ну и глупый вопрос, вы уверены, что между переходом от метода, в котором создается сессия, к следующему методу проект не перекомпилируется? :-)
Не перекомплируется.
Еще один вопрос, если сессия возвращает тип object, то почему вы пишите string test = Session["User.Project"]; Действительно такой код используете, или это просто ошибка в тексте вопроса?
А применении точки в названии ключа сессии приводит к возвращению объекта? Или как вы определили, что сессия возвращает объект? По сути должно либо string, либо int. Но потом приводится к integer (int)
Я обычно пишу на php и там нету проблем в названии ключа для сессии, с точкой или нижнем дефисом, поэтому я предположил что здесь тоже нет разницы. Но всё равно, я переписал с указанием нижнего дефиса для того, чтобы исключить его вину.
Я повторюсь, что при вызове ключа сессии в первом методе, сразу после объявления ключа, то значение он возвращает нормально. Проблемы начинаются, когда пользователь в рамках одной сессии вызывает второй метод, где данных в сессии уже нет. Я банально создал две страницы. При вызове первой, данные сохраняются в сессии. При переходе на вторую страницу, данные должны из сессии изыматься, то приходит null, как будто сессия очистилась. Возможно нужно что то сделать, чтобы данные не очищались при переходе со страницы на страницу, я не знаю.
А применении точки в названии ключа сессии приводит к возвращению объекта?
Нет. Имя ключа вообще не играет никакого значение. Это просто строка. Можно любой набор символов использовать.
Я обычно пишу на php и там нету проблем в названии ключа для сессии, с точкой или нижнем дефисом, поэтому я предположил что здесь тоже нет разницы.
Верно.
Или как вы определили, что сессия возвращает объект?
Сессия может хранить любой тип данных. Это возможно благодаря универсальному типу object.
В C#, в отличие, например от Visual Basic .NET или PHP, нельзя просто так взять и присвоить один тип к другому, если сам тип этого не предусматривает (в большинстве своем так и есть).
Я банально создал две страницы. При вызове первой, данные сохраняются в сессии.
Проект в студию! Как есть, целиком. Если большой или секретный. попробуйте повторите в голом проекте и покажите его.
Такая строчка: string test = Session["User.Project"]; не позволит компилировать проект. И при проверке, может быть использована последняя успешная версия проекта, где такой строчки кода нет.
Для получения string, правильно будет:
string test = Session["User.Project"].ToString();
Алексей Немиро: Спасибо за ответ. Проект совершенно не секретный. Я попробую еще сам покумекать над проблемой. Если не получится, отправлю на электронную почту посмотреть.
Спасибо за разъяснение по типам. Да, знаю. Мне эта особенность нравится в C#. Строгая типизация. Но конкретно в моём случае, не понятно, например, зачем использовать ToString?
Если я задаю:
Session["User.Project"] = "Привет";
Значит значение будет храниться в виде строки? Зачем мы еще используем ToString? Мы же не объект храним? Или я не прав?
Значит значение будет храниться в виде строки? Зачем мы еще используем ToString? Мы же не объект храним? Или я не прав?
Внутри Session это выглядит примерно так:
object sessionItem = "Привет";
т.е. любой добавляемый тип является object.
Если бы каждый элемент сессии имел строгий тип, то работать с ней было бы сложно. Пришлось бы делать для каждого типа отдельные методы:
Session.AddInt32("ключ", 123);
Session.AddString("ключ2", "Привет");
А потом еще методы для получения значений нужного типа.
С типом object все просто, можно даже пользовательские классы использовать (в session лучше не хранить классы, но это возможно).
Ключевое слово var используется для неявного объявления типов, т.е. тип переменной определяется компилятором автоматически, в зависимости от значения. Не всегда это можно использовать.
В случае с Session["User.Project"] = "Привет";, компилятор будет знать, что Привет является строкой (классом System.String) и сможет правильно определить исходный тип. Но присвоить типу string тип object просто так нельзя, нужно явное преобразование. У типа object есть метод GetType(), который позволяет определить текущий тип. От типа object происходят все остальные типы. В общем, сплошное ООП :-)
Соответственно, если использовать var, то тип будет определен автоматически:
var test = "Привет";
а при явном определении типа придется явно преобразовывать object в нужный тип:
// переменная sessionItem типа object
// может использоваться для хранения любых типов данных
object sessionItem = "Привет";
// переменная test типа string
// преобразуем sessionItem в строку
string test = sessionItem.ToString();
sessionItem = 123;
// переменная num типа int
// преобразуем sessionItem в int
int num = (int)sessionItem;
Алексей Немиро: Алексей. Спасибо Вам большое за помощь. Я нашёл проблему. Совершенно случайно. И в жизни бы не мог подумать что виной всему будет редирект из одной страницы на другую. Бред. Может есть этому какое то объяснение? При редиректе, видимо значения хранящиеся в сессии анулируются.
Но по опыту работы с php, я знаю что так не делается, чтобы редирект был вначале а потом уже ненужное View();
Но я подумал, что для этого надо было писать класс над контроллером, решение оказалось куда более изящнее:
return RedirectToAction("Services", "General");
Случайно исправил на RedirectToAction и данные в сессии сохранились от одного метода к другому. Бред. Почему в первом случае данные не сохранялись? В жизни бы не подумал что вина в редиректе.
Quber: Да, в MVC делать Response.Redirect будет неправильно.
Нужно использовать специально созданные для этого методы, начинающиеся со слова Redirect*. Их там целый зоопарк.
При использовании Response.Redirect, сервер не передает Cookies клиенту. Поэтому сессия теряется.
Почему... Не задумывался об этом. Правильный код использовать удобней :-) Вероятно команда Response.Redirect("~/General/Services") завершает текущий запрос (Response.End()). А работа с Session происходит в контексте MVC и после Response.End(), MVC манипулировать текущим Response уже не может. Т.е. получается, MVC находится выше, чем результат работы Response.Redirect(). Возможно, моё объяснение некорректно, но полагаю, это примерно так работает.
Вообще, в ASP.NET при работает с HTTP, в большинстве своем, нет нужды соблюдать строгий порядок действий, как в PHP. Все само делается, как нужно.
...
Сейчас проверил, у Response.Redirect есть перегрузка и вторым параметром можно указать, нужно завершать выполнение запроса или нет.