Устойчивость данных в обратных передачах ASP.NET

Контекст:

Я часто бывал в ситуациях, когда наши страницы ASP.NET должны были показывать данные пользователю в GridView, позволяя ему изменять его, как ему заблагорассудится (текстовое поле на ячейках), и только сохранять его в базе данных, когда он на самом деле нажимает кнопку "Сохранить" . Эти данные, как правило, представляют собой виртуальное состояние информации на странице, что означает, что пользователь может изменить все, не сохраняя его, пока не нажмет кнопку "Сохранить" . В таких случаях всегда есть список данных, которые необходимо сохранить в Postbacks ASP.NET. Эти данные могут быть экземпляром DataTable или всего лишь List<Someclass>.

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

Пример того, как часто используется сессия:

private List<SomeClass> DataList
{
    get
    {
        return Session["SomeKey"] as List<SomeClass>;
    }
    set 
    {
        Session["SomeKey"] = value;
    }
}

Люди часто пытаются решить это, делая что-то вроде этого:

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        DataList = null
    }
    else
    {
        FillGridView(DataList);
    }
}

Но как насчет того, что две вкладки уже загружены, и пользователь меняет значения GridView, и по какой-то странной причине он пытается сохранить данные, нажав кнопку "Сохранить" на другой странице? Мне лично не нравится этот вариант.

Другими способами сделать это можно было бы поместить данные на ViewState. Однако, когда дело доходит до сохранения существенно больших списков, это может сильно повлиять на страницу при ее сохранении на странице (HiddenField).

Но какой лучший способ сделать эту работу? Однажды я подумал, используя Session вместе с ViewState, где ViewState будет содержать уникальный идентификатор, который будет индексировать сохраненные данные Session. Это предотвратит совместное использование данных между вкладками в браузере:

private List<SomeClass> DataList
{
    get
    {
        if (ViewState["SomeKey"] == null)
        {
            ViewState["SomeKey"] = Guid.NewGuid().ToString();
        }

        return Session[ViewState["SomeKey"].ToString()] as List<SomeClass>;
    }
    set {

        if (ViewState["SomeKey"] == null)
        {
            ViewState["SomeKey"] = Guid.NewGuid().ToString();
        }

        Session[ViewState["SomeKey"].ToString()] = value;
    }
}

С другой стороны, он будет хранить новый список данных в сеансе каждый раз, когда пользователь входит на страницу. Это повлияет на память сервера. Может быть, их можно было каким-то образом стереть.

Вопрос:

Каким будет лучший способ сохранения таких данных через Postbacks, учитывая контексты нескольких вкладок в браузере, с меньшими затратами на сервер и команду кодирования обслуживания?

Update:

Как @nunespascal красиво отправлен, одним из вариантов будет сохранение ViewState в Session с помощью SessionPageStatePersister. Но, к сожалению, это не вариант по моему делу. И все же он не сильно отличается от моего последнего примера, сохраняя данные в сеансе, индексированные UniqueId, хранящиеся в ViewState.

Будут ли другие варианты?

Ответ 1

Существует простое решение этой проблемы. Храните ViewState в сеансе.

Для этого вам нужно использовать SessionPageStatePersister

Обратитесь: Страница состояния государства

Все, что вам нужно сделать, это переопределить PageStatePersister и использовать SessionPageStatePersister вместо стандартного HiddenFieldPageStatePersister

protected override PageStatePersister PageStatePersister
{
    get
    {
        return new SessionPageStatePersister(this);
    }
}

Это даже избавляет вас от головной боли при сохранении уникального ключа. Скрытое поле будет автоматически использовано для сохранения уникального ключа для каждого экземпляра страницы.

Ответ 2

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

Итак, мое решение состояло в том, чтобы разрешить изменения в базе данных, но убедитесь, что все пользователи видят одно и то же состояние через SignalR.

Теперь проблема concurrency исчезла, но вам все равно нужно внести изменения "на лету". Возможно, вы не захотите сохранять изменения. Я решил эту проблему, применив шаблон шаблона команды. Теперь любой набор изменений может быть одобрен или отменен. Всякий раз, когда вы проверяете индекс, вы увидите последнее одобренное gridview. Перейдите на страницу обновления, и вы увидите обновленное gridview. Кроме того, перейдите к изменениям, чтобы увидеть старые утвержденные gridview - другие преимущества шаблона проектирования команд -.