MVC多页表单丢失会话

时间:2012-10-17 20:08:14

标签: c# asp.net-mvc-3 forms session tempdata

我有一个用于收集潜在客户的多页表单。我们称之为广告系列的同一表单有多个版本。有些广告系列是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); }
    }

Campaign 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 visitorID。但是当发生这些错误时,Campaign POST和Submit POST之间会有一个不同的visitorID。因为我们在广告系列和提交操作期间通过TrackLead()方法跟踪每个表单提交,我可以看到会话在调用之间丢失,尽管每次POST后都会触发OnActionExecuted并将表单存储在会话中。

因此,当出现错误时,我们会在一个visitorID下获得一半表单,并在另一个visitorID下获取表单的其余部分。幸运的是,我们使用第三方服务,每次表单值更改时都会发送一个API调用,该服务使用自己的ID。这些ID在表单的前半部分和表单的其余部分之间是一致的,也是我可以从丢失的会话问题中保存潜在客户的唯一方法。

我还应该注意到99%的时间都可以正常工作。

修改 我修改了我的代码,以便在RTData中显式存储我的主要对象,并使用TempData.Keep()方法在后续请求之间保留对象。我只是将这种行为部署到我的3个站点中的一个,但到目前为止还是那么好。

我还尝试直接在Session中将我的主要对象存储在控制器动作中,即

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

使用HTTPSessionStateBase,试图绕过包装类,而不是使用HTTPSessionState的HttpContext.Current.Session。正如预期的那样,这一修改在这个问题上没有任何区别。

编辑#2: 今天早上检查我的电子邮件,我注意到两个会话错有些事情导致会话清除,很可能是某种类型的应用程序池回收,但我还没有弄明白。我可能会开始在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 个答案:

没有答案