Многостраничная форма MVC проигрышная сессия

У меня есть многостраничная форма, которая используется для сбора потенциальных клиентов. Существует несколько версий одной формы, которые мы называем кампаниями. Некоторые кампании представляют собой 3-страничные формы, другие - 2 страницы, некоторые - 1 страницу. Все они используют одну и ту же модель потенциальных клиентов и контролера кампании и т. Д. Существует 1 действие для управления потоком кампаний и отдельное действие для отправки всей информации о потенциальных клиентах в базу данных.

Я не могу воспроизвести это локально, и существуют проверки, чтобы гарантировать, что пользователи не могут пропускать страницы. Режим сеанса - InProc.

Это выполняется после каждого действия POST, которое сохраняет значения в сеансе:

    protected override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        base.OnActionExecuted(filterContext);

        if (this.Request.RequestType == System.Net.WebRequestMethods.Http.Post && this._Lead != null)
            ParentStore.Lead = this._Lead;
    }

Это свойство Lead в контроллере:

    private Lead _Lead;

    /// <summary>
    /// Gets the session stored Lead model.
    /// </summary>
    /// <value>The Lead model stored in session.</value>
    protected Lead Lead
    {
        get
        {
            if (this._Lead == null)
                this._Lead = ParentStore.Lead;

            return this._Lead;
        }
    }

Класс ParentStore:

public static class ParentStore
{
    internal static Lead Lead
    {
        get { return SessionStore.Get<Lead>(Constants.Session.Lead, new Lead()); }
        set { SessionStore.Set(Constants.Session.Lead, value); }
    }

Действие кампании POST:

    [HttpPost]
    public virtual ActionResult Campaign(Lead lead, string campaign, int page)
    {
        if (this.Session.IsNewSession)
            return RedirectToAction("Campaign", new { campaign = campaign, page = 0 });

        if (ModelState.IsValid == false)
            return View(GetCampaignView(campaign, page), this.Lead);

        TrackLead(this.Lead, campaign, page, LeadType.Shared);

        return RedirectToAction("Campaign", new { campaign = campaign, page = ++page });
    }

Проблема возникает между вышеуказанным действием и до того, как будет выполнено следующее действие Отправить:

    [HttpPost]
    public virtual ActionResult Submit(Lead lead, string campaign, int page)
    {
        if (this.Session.IsNewSession || this.Lead.Submitted || !this.LeadExists)
            return RedirectToAction("Campaign", new { campaign = campaign, page = 0 });

        lead.AddCustomQuestions();
        MergeLead(campaign, lead, this.AdditionalQuestionsType, false);

        if (ModelState.IsValid == false)
            return View(GetCampaignView(campaign, page), this.Lead);

        var sharedLead = this.Lead.ToSharedLead(Request.Form.ToQueryString(false)); //Error occurs here and sends me an email with whatever values are in the form collection.
        EAUtility.ProcessLeadProxy.SubmitSharedLead(sharedLead);
        this.Lead.Submitted = true;
        VisitorTracker.DisplayConfirmationPixel = true;

        TrackLead(this.Lead, campaign, page, LeadType.Shared);

        return RedirectToAction(this.ConfirmationView);
    }

Каждый посетитель нашего сайта получает уникальный идентификатор GUID. Но когда возникает эта ошибка, между Campaign POST и Submit POST существует другой идентификатор посетителя. Поскольку мы отслеживаем каждую отправку формы с помощью метода TrackLead() во время кампании и отправляем действия, я вижу, что сеанс теряется между вызовами, несмотря на то, что OnActionExecuted запускается после каждого POST и сохраняет форму в сеансе.

Таким образом, при возникновении ошибок мы получаем половину формы под одним идентификатором посетителя, а оставшуюся часть формы под другим идентификатором посетителя. К счастью, мы используем стороннюю службу, которая отправляет вызов API каждый раз, когда изменяется значение формы, которая использует свой собственный идентификатор. Эти идентификаторы согласуются между первой половиной формы и остальной частью формы, и единственным способом, которым я могу сохранить отрывки из потерянных проблем сеанса.

Я должен также отметить, что это работает хорошо в 99% случаев.

РЕДАКТИРОВАТЬ: я изменил свой код, чтобы явно сохранить мой ведущий объект в TempData и использовал метод TempData.Keep(), чтобы сохранить объект между последующими запросами. Я только развернул это поведение на 1 из 3 моих сайтов, но пока все хорошо.

Я также попытался сохранить свои ведущие объекты в сеансе непосредственно в действии контроллера, т.е.

Session.Add("lead", this._Lead);

который использует HTTPSessionStateBase, пытаясь обойти класс оболочки, вместо HttpContext.Current.Session, который использует HTTPSessionState. Эта модификация не внесла изменений в вопрос, как и ожидалось.

РЕДАКТИРОВАТЬ #2: проверяя мою электронную почту этим утром, я заметил две ошибки сеанса, несмотря на сохранение моей ведущей модели в TempData. Что-то заставляет сессию очиститься, скорее всего, какая-то перезагрузка пула приложений, но я пока не смог понять это. Я, вероятно, собираюсь начать сеанс в SQL Server...

Код SessionStore.cs по запросу:

public static class SessionStore
{
    private static HttpSessionState Session
    {
        get { return HttpContext.Current.Session; }
    }

    public static T Get<T>(object name, T defaultValue)
    {
        var key = name.ToString();
        return SessionStore.Session.ContainsKey(key) ? (T)Session[key] : defaultValue;
    }

    public static void Set(object name, object value)
    {
        SessionStore.Session.Add(name.ToString(), value);
    }
}

0 ответов

Другие вопросы по тегам