【问题标题】:ASP.Net MVC 3 Strange Session BehaviourASP.Net MVC 3 奇怪的会话行为
【发布时间】:2011-06-04 01:45:53
【问题描述】:

我有一个 mvc 3 应用程序,我正在使用我自己的登录视图来实现授权,该视图检查用户名和密码是否被允许,然后在会话中设置一个变量来表示用户已登录。这种的作品,但对于一个特定的观点,它的行为是一种奇怪的不受欢迎的方式。所述视图包含我用来输入一些数据和上传文件的表单。由于某种我无法弄清楚的原因,在发布此表单后,将启动一个新会话,因此记住用户已登录的变量被重置为 false,随后再次显示登录页面。

我不知道为什么应用程序此时开始一个新会话?我没有指示它这样做。谁能推荐解决方案来阻止这种行为并让它保持旧会话?

谢谢。

更新 - 一些代码:

请注意,在回复已发布的Create 表单后,会话似乎立即终止

CMS 控制器在所有操作上使用名为“RDAutorize”的自定义 Autorize 属性:

[RDAuthorize]
public class PhotoCMSController : Controller
{

public ActionResult Create()
{
    /* Code omitted: set up a newPhoto object with default state */
    /* Display view containing form to upload photo and set title etc. */
    return View("../Views/PhotoCMS/Create", newPhoto);
}

[HttpPost]
public ContentResult Upload(int pPhotoId)
{   
    /* Code ommited: receive and store image file which was posted
     via an iframe on the Create view */  
    string thumbnail = "<img src='/path/to/thumb.jpg' />";
    return Content(thumbnail);
}

[HttpPost]
public ActionResult Create(string pPhotoTitle, string pCaption etc...)
{
     /*Code omitted: receive the rest of the photo data and save
      it along with a reference to the image file which was uploaded
      previously via the Upload action above.*/

      /* Display view showing list of all photo records created */
      return View("../Views/PhotoCMS/Index", qAllPhotos.ToList<Photo>());

      /* **Note: after this view is returned the Session_End() method fires in 
       the Global.asax.cs file i.e. this seems to be where the session is
       being lost** */
}

}/*End of CMS Controller*/

自定义授权操作过滤器:

public class RDAuthorize : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        Boolean authorized = Convert.ToBoolean(
            HttpContext.Current.Session["UserIsAuthorized"]
        );

        if (!authorized) {
            /* Not logged in so send user to the login page */
            filterContext.HttpContext.Response.Redirect("/Login/Login");
        }
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext) {}
    public override void OnResultExecuting(ResultExecutingContext filterContext) {}
    public override void OnResultExecuted(ResultExecutedContext filterContext) {}

}/*End of Authorize Action Filter*/

登录控制器:

public class LoginController : Controller
{
    private PhotoDBContext _db = new PhotoDBContext();

    public ActionResult Login()
    {
        string viewName = "";
        Boolean authorized = Convert.ToBoolean(Session["UserIsAuthorized"]);
        if (authorized)
        {
            viewName = "../Views/Index";
        }
        else
        {
            viewName = "../Views/Login/Login";
        }
        return View(viewName);
    }

    [HttpPost]
    public ActionResult Login(string pUsername, string pPassword)
    {
        string viewName = "";
        List<Photo> model = new List<Photo>();

        var qUsers = from u in _db.Users
                select u;

        foreach (User user in qUsers.ToList<User>())
        {
            /* If authorized goto CMS pages */
            if (pUsername == user.Username && pPassword == user.Password)
            {
                Session["UserIsAuthorized"] = true;
                var qPhotos = from p in _db.Photos
                              where p.IsNew == false
                              select p;

                model = qPhotos.ToList<Photo>();
                viewName = "../Views/PhotoCMS/Index";
                break;
            }
        }

        return View(viewName, model);

    }

}/* End of Login controller */

【问题讨论】:

  • 很抱歉没有提前添加代码。我希望以上内容有用。
  • 感谢这篇文章,我学会了如何使用授权。

标签: asp.net session asp.net-mvc-3


【解决方案1】:

原来整个 ASP.Net 应用程序正在重新启动,因为作为照片上传的一部分,我将图像文件存储在一个临时文件夹中,然后在将文件移动到永久位置后删除该目录。显然,如果网站中的目录被删除,ASP.Net 的默认行为将重新启动。我找到了这个post 它描述了问题并提供了一个解决方案,将以下代码添加到 Global.asax.cs 文件中。实施此解决方案已解决了该问题。通过从 Application_Start() 事件调用 FixAppDomainRestartWhenTouchingFiles() 来应用修复:

    protected void Application_Start()
    {
        FixAppDomainRestartWhenTouchingFiles();
    }

    private void FixAppDomainRestartWhenTouchingFiles()
    {
        if (GetCurrentTrustLevel() == AspNetHostingPermissionLevel.Unrestricted)
        {
            /* 
             From: http://www.aaronblake.co.uk/blog/2009/09/28/bug-fix-application-restarts-on-directory-delete-in-asp-net/
             FIX disable AppDomain restart when deleting subdirectory
             This code will turn off monitoring from the root website directory.
             Monitoring of Bin, App_Themes and other folders will still be 
             operational, so updated DLLs will still auto deploy.
            */

            PropertyInfo p = typeof(HttpRuntime).GetProperty(
                "FileChangesMonitor", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
            object o = p.GetValue(null, null);
            FieldInfo f = o.GetType().GetField(
                "_dirMonSubdirs", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.IgnoreCase);
            object monitor = f.GetValue(o);
            MethodInfo m = monitor.GetType().GetMethod(
                "StopMonitoring", BindingFlags.Instance | BindingFlags.NonPublic);
            m.Invoke(monitor, new object[] { });
        }
    }

    private AspNetHostingPermissionLevel GetCurrentTrustLevel()
    {
        foreach (AspNetHostingPermissionLevel trustLevel in
            new AspNetHostingPermissionLevel[] {
                AspNetHostingPermissionLevel.Unrestricted,
                AspNetHostingPermissionLevel.High,
                AspNetHostingPermissionLevel.Medium,
                AspNetHostingPermissionLevel.Low,
                AspNetHostingPermissionLevel.Minimal }
            )
        {
            try
            {
                new AspNetHostingPermission(trustLevel).Demand();
            }
            catch (System.Security.SecurityException)
            {
                continue;
            }

            return trustLevel;
        }

        return AspNetHostingPermissionLevel.None;
    }

【讨论】:

  • 糟糕的解决方案设计(例如删除一些目录)让我们更好地了解 asp.net 基础设施 :) 感谢您提供有关 asp.net 文件系统监视器工作的详细信息(它负责重新编译更改的视图, 当代码文件/dll 的/web.config 或文件夹结构发生更改时重新启动,以及 asp.net 缓存的文件依赖项可能是其他的)。遗憾的是,没有一个受访者有机会解决这个问题。但是请不要使用这个 hack,将此临时目录添加到项目中并且不要删除它。
【解决方案2】:

由于会话与 cookie 相关联,因此它们可用于特定域。

当域发生变化(即重定向到子域)时,在同一应用程序中请求会话变量是一个常见错误。

【讨论】:

  • 这是 Xaqron 的一个有趣点。但是我使用的视图都遵循这个 url 模式:localhost:port/controller/viewname 所以我认为这意味着它们都在同一个域中。
  • 由于会话丢失,可能有两个原因。 1)它不存在(w3p 已终止,这不常见) 2)它存在但您无法访问它(这很常见)。希望这会有所帮助。
【解决方案3】:

您发布表单的控制器操作是否包含任何 [Authorize] 属性。您需要发布一些代码。

【讨论】:

  • 是的,我正在使用自定义 [Authorize] 属性。我已经编辑了我的问题以包含一些代码。如果您能看一看,将不胜感激。
  • 我无法找出代码中的任何问题。您是否在使用某些地方 Response.End()?您是否在任何 HTTP 发布后失去会话?
  • Session_End() 在 HTTP Post 期间或之后立即被触发到 Create Action Result 方法。
  • 我没有使用任何 Response.End()。
【解决方案4】:
  1. 每次都验证一个新会话是否真的开始了。检查用户会话 ID 的跟踪输出,以确保它确实已更改。
  2. 确保发送过来的 cookie 实际上已设置并发送过来。 (称为 ASPsessionIDSOMETHING )以及是否由浏览器发送。下载工具 Fiddler 以轻松检查 cookie(设置来自服务器的 cookie 标头和从浏览器返回服务器的请求 cookie。确保您的浏览器正在接受 cookie,并且您没有说...关闭了 cookie。
  3. 如果您的会话 ID 在每次请求时都在更改,那么您的会话第一次没有正确设置,如果您还没有设置断点,请在该代码上设置一个断点。
  4. 您可以在工作进程重置时记录 - 确保不是这种情况。见http://www.microsoft.com/technet/prodtechnol/windowsserver2003/library/IIS/87892589-4eda-4003-b4ac-3879eac4bf48.mspx

【讨论】:

  • 会话 ID 没有改变,但我知道会话正在结束并且正在启动一个新会话,因为我的 Global.asax.cs 文件中的 Session_Start() 和 Session_End() 方法中有断点。如果您能查看我刚刚添加的代码,我将不胜感激。与此同时,我会看看你的其他建议。
  • Cookies 在我的浏览器中肯定打开了。
  • 那么它可能是同一个会话,你可能会遇到这个问题:stackoverflow.com/questions/3365942/…
【解决方案5】:

我遇到了同样的问题。仅当将发布请求发送到服务器并且在该请求期间未修改会话时才会出现此问题。我作为一种解决方法所做的是,编写一个自定义过滤器,它只不过是在每个请求的会话中写入一个键/值,并将该过滤器添加到 global.asax 中的 GlobalFilter 集合中。

public class KeepSessionAlive : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if(filterContext.HttpContext.Session != null)
        {
            filterContext.HttpContext.Session["HeartBeat"] = DateTime.Now.ToShortDateString();
        }
}

    public void OnActionExecuted(ActionExecutedContext filterContext) { }

}

在 global.asax 中:

protected override void AddCustomGlobalFilters(GlobalFilterCollection filters)
{
   filters.Add(new KeepSessionAlive());
}

这可能不是最好的解决方案,但它对我的情况有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-27
    • 2014-03-03
    相关资源
    最近更新 更多