繁体   English   中英

ASP.NET MVC - 在控制器之间共享会话状态

[英]ASP.NET MVC - Sharing Session State Between Controllers

我仍然大多不熟悉控制反转(虽然我现在正在学习它)所以如果这是我的问题的解决方案,请告诉我,我会回过头来学习它。

我有一对控制器需要一个Session变量,自然没有什么特别的事情发生,因为Session首先工作,但这让我想知道在两个独立的控制器之间共享相关对象最干净的方法是什么。 在我的特定场景中,我有一个UploadController和一个ProductController,它们相互配合使用来上传图像文件。 当UploadController上传文件时,有关上传的数据存储在Session中。 发生这种情况后,我需要在ProductController中访问该Session数据。 如果我在两个控制器中为包含我的上传信息的Session变量创建一个get / set属性,我将能够访问该数据,但同时我将违反各种DRY,更不用说创建一个,充其量,令人困惑的设计,其中一个对象由两个完全断开连接的对象共享和修改。

你有什么建议?

确切的背景:

文件上载View将文件发布到UploadController.ImageWithpreview(),然后读取已发布的文件并将其复制到临时目录。 保存文件后,另一个类生成上传图像的缩略图。 然后,使用JsonResult将原始文件和生成的缩略图的路径返回到javascript回调,该回调更新页面上可以“已保存”或“已取消”的表单中的某些动态内容。 无论上传的图像是保存还是被跳过,我都需要从临时目录中移动或删除它和生成的缩略图。 为此,UploadController在Session维护的Queue对象中跟踪所有上传文件及其缩略图。

返回视图:在使用生成的图像缩略图填充表单后,表单将回发到ProductsController,其中标识了所选文件(目前我将文件名存储在隐藏字段中,我意识到这是一个可怕的漏洞),然后从临时目录复制到永久位置。 理想情况下,我想简单地访问我存储在Session中的队列,这样表单就不需要像现在一样包含图像位置。 这就是我设想我的解决方案的方式,但我会热切地倾听任何评论或批评。

我想到了几个解决方案。 您可以使用映射到请求的“SessionState”类并获取/设置信息(我从内存中执行此操作,因此这不太可能编译并且意味着传达这一点):

internal class SessionState
{
  string ImageName
  {
    get { return HttpContext.Current.Session["ImageName"]; }
    set { HttpContext.Current.Session["ImageName"] = value; }
  }
}

然后从控制器,执行以下操作:

  var sessionState = new SessionState();
  sessionState.ImageName = "xyz";
  /* Or */
  var imageName = sessionState.ImageName;

或者,您可以创建控制器扩展方法:

public static class SessionControllerExtensions
{
  public static string GetImageName(this IController controller)
  {
    return HttpContext.Current.Session["ImageName"];
  }

  public static string SetImageName(this IController controller, string imageName)
  {
    HttpContext.Current.Session["ImageName"] = imageName;
  }
}

然后从控制器:

  this.SetImageName("xyz");
  /* or */
  var imageName = this.GetImageName();

这肯定是干的。 也就是说,我并不特别喜欢这些解决方案中的任何一个,因为我更喜欢在会话中存储尽可能少的数据(如果有的话)。 但是如果你的意图是保留所有这些信息而不必从其他来源加载/辨别它,这是我能想到的最快(最脏)的方式。 我非常肯定有一个更优雅的解决方案,但我没有关于你正在尝试做什么以及问题域是什么的所有信息。

请记住,在会话中存储信息时,您必须通过序列化对对象进行脱水/再水化,并且您可能无法通过这种方式获得您认为自己的性能。

希望这可以帮助。

编辑:回应其他信息不确定你要在哪里部署它,但处理图像“实时”是一个肯定的火灾方式被DoS攻击击中。 我给你的建议如下 - 假设这是面向公众的,任何人都可以上传图片:

1)允许用户上传图像。 该图像进入处理队列以供应用程序或某些服务进行后台处理。 此外,图像的名称会进入用户的个人处理队列 - 可能是数据库中的表。 有关Web应用程序中后台处理的信息,请参阅@ 在托管Web服务器中安排作业

2)处理这些图像,并在处理时显示“处理图形”。 您可以在产品页面上有一个ajax请求,用于检查正在处理的图像,并尝试每隔X秒重新加载一次。

3)当图像被“处理”时,用户可以选择退出处理,假设他们是上传图像的那个。 这可以在显示图像的产品页面上显示,也可以在单独的“用户队列”视图中使用,以便从图像中删除图像。

因此,您最终会得到更多域对象,并且这些对象由队列管理。 我是约会优于配置的强烈倡导者,因此应预先定义产品图像的最终目的地。 就像是:

images / products / {id} .jpg或者,如果是集合,images / products / {id} / {sequence} .jpg。

然后,您无需知道表单中的目的地。 所有图像都是一样的。

然后,队列需要知道临时图像的上传位置以及产品ID。 队列工作程序从队列中弹出项目,处理它们并相应地存储它们。

我知道这听起来比你原定的更“结构化”,但我认为它更清洁一些。

UploadController和ProductController之间是否完全等价?

当UploadController上传文件时,有关上传的数据存储在Session中。 发生这种情况后,我需要在ProductController中访问该Session数据。

当我读到UploadControl需要对上传数据的读写访问时,ProductController只需要读取。

如果这是真的那么你可以通过在上传信息周围使用一个不可移动的包装器并让UploadController将它放入会话中来表明它。

会话本身定义为公共共享布告板,以允许任何人获取和放置的成本分离显式关系。 您可以允许ProductController了解UploadController,因此无需通过会话传递上载信息。 我的直觉是上传信息对公众很有趣,所以使用Session是合理的。

我没有看到任何DRY违规行为,我们明确地试图分离责任。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM