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

时间:2009-08-11 04:03:54

标签: asp.net-mvc design-patterns inversion-of-control

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

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

你有什么建议?

确切上下文:

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

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

2 个答案:

答案 0 :(得分:3)

我想到了几个解决方案。您可以使用映射到请求的“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应用程序中后台处理的信息,请访问@ Schedule a job in hosted web server

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

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

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

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

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

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

我知道这听起来比你原先想要的更“结构化”,但我觉得它更清洁。

答案 1 :(得分:1)

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

  

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

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

如果这是真的,那么你可以通过在上传信息周围使用免疫包装器并让UploadController将其放入会话中来明确它。

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

我在这里看不到任何DRY违规行为,我们明确地试图将责任分开。