ASP.NET会话在更新时线程之间没有同步?

时间:2012-01-20 18:25:36

标签: asp.net session thread-safety asp.net-mvc-4

我有一个返回一些JSON的控制器方法。它将一个集合从会话中拉出来,从集合中取出第一个项目,然后从集合中删除它。如果方法开头的计数为1,则现在为0。

如果我以相同的方法再次从会话中检索集合,以检查集合计数是否少于1,那么它就是。

到目前为止简单的事情。

在随后的请求中,再次从会话中提取集合,但是没有按预期计数0,它具有1.先前删除的项目尚未被删除!这是为什么?

虽然如果有足够的请求,计数确实最终为零。这就好像会话对象需要30秒左右才能在所有线程之间同步。

真的可以吗? MVC4(也可能是以前的版本吗?)有一些奇怪的会话同步问题吗?

我正在使用默认的InProc会话提供程序和设置。

这是日志:

Thread  Level   Logger  Message
23  DEBUG   ProjectMvc.Controllers.RpcController    Pre-processing - Tasks.Count: 1
23  DEBUG   ProjectMvc.Controllers.RpcController    Post processing - SessionID: asaq1v5afu0pwz13at4a24hl
23  DEBUG   ProjectMvc.Controllers.RpcController    Post processing - Tasks.Count: 0

16  DEBUG   ProjectMvc.Controllers.RpcController    Pre-processing - Tasks.Count: 1
16  DEBUG   ProjectMvc.Controllers.RpcController    Post processing - SessionID: asaq1v5afu0pwz13at4a24hl
16  DEBUG   ProjectMvc.Controllers.RpcController    Post processing - Tasks.Count: 0

23  DEBUG   ProjectMvc.Controllers.RpcController    Pre-processing - Tasks.Count: 1
23  DEBUG   ProjectMvc.Controllers.RpcController    Post processing - SessionID: asaq1v5afu0pwz13at4a24hl
23  DEBUG   ProjectMvc.Controllers.RpcController    Post processing - Tasks.Count: 0

24  DEBUG   ProjectMvc.Controllers.RpcController    Pre-processing - Tasks.Count: 1
24  DEBUG   ProjectMvc.Controllers.RpcController    Post processing - SessionID: asaq1v5afu0pwz13at4a24hl
24  DEBUG   ProjectMvc.Controllers.RpcController    Post processing - Tasks.Count: 0

9   DEBUG   ProjectMvc.Controllers.RpcController    Pre-processing - Tasks.Count: 1
9   DEBUG   ProjectMvc.Controllers.RpcController    Post processing - SessionID: asaq1v5afu0pwz13at4a24hl
9   DEBUG   ProjectMvc.Controllers.RpcController    Post processing - Tasks.Count: 0

14  DEBUG   ProjectMvc.Controllers.RpcController    Pre-processing - Tasks.Count: 1
14  DEBUG   ProjectMvc.Controllers.RpcController    Post processing - SessionID: asaq1v5afu0pwz13at4a24hl
14  DEBUG   ProjectMvc.Controllers.RpcController    Post processing - Tasks.Count: 0

如果我无法弄清楚为什么会话中的集合没有针对其他请求进行更新,我将不得不解决它并将这些内容存储在数据库中。

以下是代码:

    public ActionResult GetCoordinatesTask()
    {
        var user = Session["User"] as IUser;
        if (user == null)
        {
            Logger.LogError(this, "No user in session!");
            return Json(null, JsonRequestBehavior.AllowGet);
        }

        if (user.PhotoGeocodingTasks == null || user.PhotoGeocodingTasks.Count == 0)
            return Json(null, JsonRequestBehavior.AllowGet);

        lock (user.PhotoGeocodingTasks)
        {
            Logger.LogDebug(this, "Pre-processing - PhotoGeocodingTasks.Count" + user.PhotoGeocodingTasks.Count);

            var task = user.PhotoGeocodingTasks[0];
            if (!user.PhotoGeocodingTasks.Remove(task))
                Logger.LogError(this, "Could not remove geocoding task after picking it up!");

            var encodedTask = new Dictionary<string, string>
            {
                {"photoid", task.PhotoId.ToString(CultureInfo.InvariantCulture)},
                {"latlong", task.Latitude + "," + task.Longitide}
            };

            Logger.LogDebug(this, "Post processing - SessionID: " + Session.SessionID);
            Logger.LogDebug(this, "Post processing - PhotoGeocodingTasks.Count" + user.PhotoGeocodingTasks.Count);

            return Json(encodedTask, JsonRequestBehavior.AllowGet);
        }
    }

修改

以下是我在web.config上进行会话的内容:

<sessionState mode="InProc" customProvider="DefaultSessionProvider">
        <providers>
            <add name="DefaultSessionProvider" type="System.Web.Providers.DefaultSessionStateProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        </providers>
    </sessionState>

修改2

我也尝试将此任务数据存储在HttpRuntime.Cache中(键入用户ID)并获得相同的结果。没有其他请求的更新值。就像在我的配置中禁用同步一样。

我在两台计算机上也尝试过这个代码,结果相同。

2 个答案:

答案 0 :(得分:1)

我在这里看不到这种行为。你能试试我的样品吗?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using NLog;
using System.Globalization;
using System.Threading;

namespace Mvc4Application.Controllers
{
    public class GeoCodingTask
    {
       public string  Photoid{get;set;}
    }

    public class User
    {
        public List<GeoCodingTask> PhotoGeocodingTasks {get;set;}
    }

    public class HomeController : Controller
    {
        private static Logger _logger = LogManager.GetCurrentClassLogger();

        public ActionResult SetupCoordinatesTask()
        {   
                User  user = new User{ PhotoGeocodingTasks = new List<GeoCodingTask>()};
                 user.PhotoGeocodingTasks.Add(new GeoCodingTask{ Photoid= "id1"});
                 user.PhotoGeocodingTasks.Add(new GeoCodingTask { Photoid = "id2" });
                Session["User"] = user ;

            return View("GetCoordinatesTask");
        }

        public ActionResult GetCoordinatesTask()
        {
            User user = (User)Session["User"];
            if (user == null)
            {
                _logger.Error("No user in session!");
                return View();
            }
            if (user.PhotoGeocodingTasks == null )
                _logger.Debug("PhotoGeocodingTasks - null " );
            if (user.PhotoGeocodingTasks.Count == 0)
            {
                _logger.Debug("Pre-processing - PhotoGeocodingTasks.Count" + user.PhotoGeocodingTasks.Count);
                return View();
            }
            lock (user.PhotoGeocodingTasks)
            {
                _logger.Debug("Pre-processing - PhotoGeocodingTasks.Count" + user.PhotoGeocodingTasks.Count);
                var task = user.PhotoGeocodingTasks[0];
                if (!user.PhotoGeocodingTasks.Remove(task))
                    _logger.Error("Could not remove geocoding task after picking it up!");

                _logger.Debug("Post processing - SessionID: " + Session.SessionID);
                _logger.Debug("Post processing - PhotoGeocodingTasks.Count" + user.PhotoGeocodingTasks.Count);
                return View();
            }
        }

    }
}

我先拨打http://localhost:1631/home/SetupCoordinatesTask设置会话,然后再拨2次http://localhost:1631/home/GetCoordinatesTask

结果是

thread:19|2012-01-20 22:12:51.0492|DEBUG|Mvc4Application.Controllers.HomeController|Pre-processing - PhotoGeocodingTasks.Count2
thread:19|2012-01-20 22:12:51.0652|DEBUG|Mvc4Application.Controllers.HomeController|Post processing - SessionID: e4tawytx2mfq2msc3y2ajzl3
thread:19|2012-01-20 22:12:51.0652|DEBUG|Mvc4Application.Controllers.HomeController|Post processing - PhotoGeocodingTasks.Count1
thread:10|2012-01-20 22:13:01.0928|DEBUG|Mvc4Application.Controllers.HomeController|Pre-processing - PhotoGeocodingTasks.Count1
thread:10|2012-01-20 22:13:01.0928|DEBUG|Mvc4Application.Controllers.HomeController|Post processing - SessionID: e4tawytx2mfq2msc3y2ajzl3
thread:10|2012-01-20 22:13:01.0928|DEBUG|Mvc4Application.Controllers.HomeController|Post processing - PhotoGeocodingTasks.Count0
thread:15|2012-01-20 22:13:02.6698|DEBUG|Mvc4Application.Controllers.HomeController|Pre-processing - PhotoGeocodingTasks.Count0

您能简化一下内容代码并发布完整样本吗?

答案 1 :(得分:1)

开发人员错误。令人尴尬,但我有一个错误,我在处理完最后一个任务后继续创建一个新任务。我很想删除这个问题:)

感谢您在Malcom的所有时间。