2009-08-11 151 views
6

我仍然大多不熟悉控制反转(尽管我现在正在了解它),所以如果这是我的问题的解决方案,请让我知道,我会得到回到了解它。ASP.NET MVC - 在控制器之间共享会话状态

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

你有什么建议?

精确语境:

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

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

回答

3

想到了一些解决方案。你可以使用一个“SessionState的”类映射到请求和获取/设置信息本身(我从内存这样做,所以这是不可能的编译,是为了传达点):

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

然后从控制器,这样做:从控制器

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; 
    } 
} 

然后:

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

或者,你可以创建一个控制器扩展方法

这当然是干的。也就是说,我并不特别喜欢这些解决方案,因为我喜欢在会话中存储少量数据(如果有的话)。但如果你的意图是坚持所有这些信息,而不必从其他来源加载/辨别它,这是我能想到的最快(最肮脏)的方式。我相当确定有一个更加优雅的解决方案,但是我没有关于您要做什么以及问题域是什么的所有信息。

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

希望这会有所帮助。

编辑:为了应对更多的信息 上,你正在寻找部署这一点,但处理图像不知道“实时”是一个确保消防方式与DoS攻击击中。我对你的建议如下 - 这是假设这是公开的,任何人都可以上传图片:

1)允许用户上传图片。该图像进入处理队列以供应用程序或某种服务进行后台处理。此外,图像的名称会进入用户的个人处理队列 - 可能是数据库中的一张表。关于网络应用程序中的后台处理信息可以在以下网址找到:Schedule a job in hosted web server

2)处理这些图像,并在处理时显示“处理图形”。您可以在产品页面上发出ajax请求,检查正在处理的图像,并每隔X秒重新装入一次。

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

所以,你最终会得到更多的域对象,并且这些对象由队列管理。我强烈支持约定配置,因此应该预先定义产品图像的最终目的地。例如:

图片/产品/ {id} .jpg或如果收集图片/产品/ {id}/{sequence} .jpg。

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

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

我知道这听起来比你最初想要的更“结构化”,但我认为它有点清洁。

+0

谢谢你的输入。如果有任何进一步的使用,我已经在原始问题中添加了更多信息。 – 2009-08-11 05:03:18

+0

图像处理是实时的,但存在于网站的管理区域内,因此它的整体使用量非常小。在整个应用程序中,每小时最多只能处理几张图像。 我还考虑过的另一种方法是简单地让应用程序的Session_End事件删除当前会话的整个临时目录,但我不确定这是多么理想。 – 2009-08-11 05:28:09

+0

如果您的用户上传了大量正在处理的图片,我认为您不能保证在会话到期时完成。一旦“处理”完成,我会删除它。只要队列中有要处理的项目,工作线程就应该保持活动状态,以便可以安全地进行处理。只要你的应用程序池不“睡”,你的系统应该继续处理好。很确定它在我链接的文章中有介绍。 – andymeadows 2009-08-11 05:56:23

1

UploadController和ProductController之间是否有完全等价的关系?

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

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

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

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

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

+0

我不确定这是否可以作为DRY问题或只是定义不良的组件通信。会话显然是为弥补我想填补的确切空白而设计的,在这种情况下,它并不觉得特别干净。 – 2009-08-11 08:30:33