2010-08-18 63 views
2

tldr>一旦选择了客户,所有其他控制器如何在客户的“上下文”中始终执行其操作,而无需手动传递ID?ASP.NET MVC:在页面之间传递价值

我想弄清楚'正确'的方式是处理一个整个控制器(或更多)都依赖于前一个控制器的想法的情况。例如,假设您正在构建某种客户管理系统。会有各种各样的客户功能,可能位于CustomerController上。但是当你进入订单管理时,你可能想要一个OrderController。

如果你只有一个OrderController,你的方法可能会是这样的:

公众的ActionResult编辑(串号){...}

的ID是订单的ID,对不对?当我需要回到客户那里时,我有些失落。这就像发生在顾客身上的所有行为的“背景”一样。你可以通过不断添加客户ID到行动(URL)的做到这一点:

http://site.com/Orders/Edit/1234?customerId=abc

但这似乎它变得相当繁琐要抓住这个值和干扰到它的每一个动作。有像Session这样的选项,但似乎马虎。

什么是正确的方法来做到这一点?

+2

你为什么认为使用会话是马虎?听起来像是一个完美的用例。 – Necros 2010-08-18 02:05:16

+1

我想我只是通过这种方式查看会话。是的,它会在这里工作,但是如果你尝试扩展等等,那么会出现问题。我通常以避免使用全局变量的方式来避开会话 - 它们可以工作,但它们有它们自己的问题。 – Jim 2010-08-18 02:27:04

+0

使用会话的另一个重要因素是用户无法为任何子页面添加书签,因为它们需要创建该上下文。通过在URL中嵌入您需要的所有内容,用户可以直接回到他们想要的任何页面。 – Jim 2010-08-19 02:57:28

回答

0

如果你真的想避免你的值存储到会话中,你可以使用一个动作过滤器均采用值的照顾。我用过这种方法一次,它是这样的:

  1. 创建一个包含您的值的占位符的新路线,例如,客户ID。
  2. 选择客户后,添加要路由的下一个GET或POST呼叫的ID。
  3. 创建一个动作过滤器,该动作过滤器从路由读取id并在动作发生之前将其添加到动作参数(OnActionExecuting)。当操作完成时,相同的过滤器将操作参数中的标识添加回路由数据(OnActionExecuted)。
  4. 使用这个新的动作过滤器,无论你希望,可能在控制器级别。

现在,即使您不手动将其添加到所有链接,您的客户ID也很容易保留在网址中。如果您需要在操作方法中使用客户ID,则只需添加具有正确名称的参数即可。即使您不将其作为参数,它仍会保留在操作方法调用之上。

如果您想更进一步,在新的操作过滤器中,您可以从数据库获取数据并将其添加到操作参数中,而不是仅添加标识。这样你可以进一步简化你的操作方法。

3

您可以通过在会话中编写一个包装来减少一般会话的松散度,这会暴露强类型属性。

//Sloppy weak typing: 
int userId = (int)HttpContext.Current.Session["UserId"]; 

//Strongly typed goodness 
int userId = SessionWrapper.UserId; 
+0

是的,当我玩弄这条路线时,我已经将几种方法烘焙到基础控制器中来完成这个任务。确实让它好一点。尽管如此,一旦这种情况发生在3台服务器上,我就会遇到一个棘手的问题。从来没有与Sql会话存储扩展的好运。 – Jim 2010-08-18 04:11:12

+1

我很确定这是一个解决的问题,有一种方法可以将会话存储在SQL Server中,以便它可以在群集中保存。也许这可能是有用的:http://support.microsoft.com/kb/317604 – 2010-08-18 04:34:45

+1

是的,它存在,它只是负荷很重。 – Jim 2010-08-18 05:18:53

0

会话是一个存储这样的东西的地方。

您也可以使用扩展性好的分布式缓存(http://msdn.microsoft.com/library/cc645013.aspx)。来自以上链接的示例代码

// CacheFactory class provides methods to return cache objects 
// Create instance of CacheFactory (reads appconfig) 
DataCacheFactory fac = new DataCacheFactory(); 
// Get a named cache from the factory 
DataCache catalog = fac.GetCache("catalogcache"); 
//------------------------------------------------------- 
// Simple Get/Put 
catalog.Put("toy-101", new Toy("thomas", .,.)); 
// From the same or a different client 
Toy toyObj = (Toy)catalog.Get("toy-101"); 
// ------------------------------------------------------ 
// Region based Get/Put 
catalog.CreateRegion("toyRegion", true); 
// Both toy and toyparts are put in the same region 
catalog.Put("toy-101", new Toy(.,.), "toyRegion"); 
catalog.Put("toypart-100", new ToyParts(…), "toyRegion"); 
Toy toyObj = (Toy)catalog.Get("toy-101", "toyRegion"); 
0

将会话信息序列化为加密会话cookie是另一种解决方案。做的好处是避免服务器资源的消耗,达到同样的目标的能力:

private void setSessionCookie() { 
     HttpCookie ck = new HttpCookie(XConstants.X_SESSION_COOKIE_KEY) { 
      Expires = DateTime.Now.AddMinutes(_sessionInfo.SessionTimeoutMinutes) 
     }; 
     DateTime now = DateTime.UtcNow; 
     _sessionInfo.SessionLastValidatedAt = now; 
     ck.HttpOnly = true; // server-only cookie 
     ck["LastCheck"] = now.ToString(XConstants.XDATEFORMAT); 
     ck["Content"] = new Cipher().Encrypt(Serializer.Serialize(_sessionInfo).OuterXml, 
      ConfigurationManager.AppSettings[XConstants.X_APPKEY_KEY]); 
     System.Web.HttpContext.Current.Response.Cookies.Add(ck); 
    }