Режим сеанса ServerState не обрабатывает сеанс в потоке должным образом

Я выполнил некоторую работу, которая добавляет значения к состоянию сеанса внутри потока. Я бы хотел, чтобы эти значения были доступны вне потока (очевидно).

Информация, добавленная к сеансу, доступна вне сеанса без каких-либо проблем, когда режим состояния сеанса - «InProc».

Однако, когда режим состояния сеанса установлен на «StateServer», поведение отличается. Обычно значения, установленные внутри потока, сохраняются иногда, а иногда нет. Мне это кажется случайным.

Вот код, который воспроизводит проблему.

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
    }

    protected void store_Click(object sender, EventArgs e)
    {
        // Set the session values to default.
        Session["Test1"] = "No";
        Session["Test2"] = "No";

        // Set the Test1 session value in the thread.
        ThreadObject threadObject = new ThreadObject() { Username = Page.User.Identity.Name, SessionState = Session };
        worker = new Thread(new ParameterizedThreadStart(Work));
        worker.Start(threadObject);

        // Set the Test2 session value in this thread just to compare.
        Session["Test2"] = "Yes";
    }

    protected void print_Click(object sender, EventArgs e)
    {
        // Print out the Session values.
        label1.Text = string.Empty;
        label1.Text += "Inside Thread: " + Session["Test1"] + ",  \n";
        label1.Text += "Outside: " + Session["Test2"] + "\n";
    }

    private static Thread worker;

    public static void Work(object threadObject)
    {
        // Retrieve the Session object and set the Test2 value.
        ThreadObject threadObject1 = (ThreadObject)threadObject;
        HttpSessionState currentSession = threadObject1.SessionState;
        currentSession["Test1"] = "Yes";
    }
}

public class ThreadObject
{
    public string Username { get; set; }
    public HttpSessionState SessionState { get; set; }
}

Приведенный выше код отлично работает с SessionState mode = "InProc", но случайный с:

<sessionState mode="StateServer"
  stateConnectionString="tcpip=localhost:42424"
  cookieless="false"
  timeout="20"/>

Любые идеи?

РЕДАКТИРОВАТЬ: Итак, согласно комментариям ниже, поток должен завершиться до завершения запроса (основного потока), иначе все, что добавлено к сеансу, будет потеряно. Это связано с тем, что в конце основного потока сеанс сериализуется и отправляется в хранилище данных (вне процесса или SQL Server).


person Ivan    schedule 25.02.2013    source источник


Ответы (1)


Я думаю, что это проблема времени - нет никакой гарантии, что ваш рабочий поток будет выполнен к тому времени, когда вы установите значения своей метки. Для создания и запуска проступи требуется несколько мс. К тому времени оставшаяся часть вашего основного потока, вероятно, будет завершена. Вы можете проверить это, поместив отладочные данные и просмотрев порядок, в котором выполняется ваш код.

Если вам нужно гарантировать, что код в вашем потоке выполняется (что устраняет необходимость в потоке), вы можете использовать метод потоковой передачи WaitOne (), чтобы ваш основной поток ожидал возврата рабочего потока. Но зависеть от значения, установленного в потоке, быть доступным в параллельном процессе - это рискованно.

Вдобавок - ИМХО, я бы не стал использовать потоки в приложениях ASP.NET - я считаю, что все согласны с тем, что они немного опасны. Я видел сбои пула приложений из-за плохого кода внутри порожденного потока.

person Ripside    schedule 25.02.2013
comment
Я думаю, вы правы с состоянием гонки, но многопоточность может быть важна и для ASP.NET. Нет ничего плохого, если правильно реализовать и использовать. Если позволить главному потоку ASP.NET ожидать чего-либо, поток станет доступным для обработки других запросов - вот почему MVC разрешает Task ‹ActionResult›. - person TGlatzer; 25.02.2013
comment
Я не могу не согласиться - даже если ваше предостережение - при правильной реализации кажется распространенной проблемой :-) - person Ripside; 25.02.2013
comment
Эй, ну, код настройки метки является частью нажатия кнопки, и я ждал более нескольких секунд, прежде чем попытаться распечатать значения сеанса на этикетке. Так что я не уверен, что это проблема времени. Повторное нажатие кнопки print_Click должно в конечном итоге позволить потоку установить свое значение в сеансе. - person Ivan; 25.02.2013
comment
Вы следите за результатами отладки? Любые ошибки исключения HTTP? Основной поток может завершиться до завершения рабочего потока, поэтому значение никогда не устанавливается. Во всяком случае, последовательно. Как я предлагал, поместите некоторые выходные данные отладки (System.Diagnostics.Debug.WriteLine (output str); или Trace.WriteLine в каждый метод и посмотрите, что запускается и когда - хотя я не думаю, что выходные данные отладки не гарантируются по порядку либо в многопоточных ситуациях. - person Ripside; 25.02.2013
comment
Я смог воспроизвести это. Помогает ли этот вопрос StackOverflow? Он предлагает проверить, включены ли у вас веб-сады (и отключить их, если это так). stackoverflow.com/ questions / 2147578 / - person Ripside; 25.02.2013
comment
Так что, @Ripside, возможно, вы правы, что это какая-то проблема времени. Я попытался использовать делегат потока вместо правильного потока для запуска кода, и у меня больше нет проблемы: ThreadPool.QueueUserWorkItem (делегат (состояние объекта) {HttpSessionState s = state as HttpSessionState; s [Test1] = Yes;} , Сессия); Хм, я все еще не знаю, что происходит, но должно быть что-то во внутреннем устройстве о том, как ASP ставит в очередь или блокирует состояние сеанса и устанавливает его значения. Любые идеи были бы хороши, но пока я счастлив :) - person Ivan; 26.02.2013
comment
Вы запускаете это локально только в VS или на сервере? На сервере все может быть немного иначе. Мне любопытно, если я сам столкнусь с этим. - person Ripside; 26.02.2013
comment
Хорошо, я думаю, что знаю, что происходит. Кажется, что в конце запроса страницы сеанс сериализуется в ServerState или SQLServer и отправляется. Итак, если фоновый поток к этому времени не поместил свои значения в сеанс, эти значения будут потеряны. Корабль отплыл, самолет взлетел: P Я проверил это, добавив Thread.Sleep (2000) к моему основному потоку, и теперь значения всегда присутствуют, потому что у фонового потока есть время сделать свое дело. Это не очень хорошо документированный атрибут режима StateServer Session :) - person Ivan; 26.02.2013
comment
Я согласен, похоже на то, что происходит. Распределение потоков в ASP.Net может быть деликатным занятием. - person Ripside; 26.02.2013