2012-07-13 28 views
48

我需要在会话中(或者在ASP.NET Web API中)存储我需要在每个API请求中检索的一些信息。我们将有一个api IIS网站,并通过主机头添加多个网站绑定。例如,当有任何请求进入时,api.xyz.com将检查主机头并将该网站信息存储在会话中,以便在对数据库进行调用时用于每个后续api请求。ASP.NET Web API会话什么的?

我知道ASP.NET Web API中不支持会话。有没有其他办法来处理这种情况?我可以在哪里存储可在每个后续请求中检索的信息?

谢谢。

回答

69

那么,设计中的REST是无状态的。通过添加会话(或其他类型的任何其他类型),您将使其成为有状态的,并打败拥有RESTful API的任何目的。

RESTful服务的整体思路是,每个资源使用通用语法在超媒体的使用是唯一可寻址链接每个HTTP请求应为它的接收方处理它是完全和谐本身携带足够的信息与HTTP的”无状态特性。

所以,无论你想在这里使用Web API做的,应该最有可能被重新architectured如果你想有一个RESTful API。

随着中说,如果你仍然愿意沿着这条路走下去,这是一种冒险的方式裂变与Web API,并且它已经发布的伊姆兰这里http://forums.asp.net/t/1780385.aspx/1

代码(虽然我不会真的建议):

public class MyHttpControllerHandler 
    : HttpControllerHandler, IRequiresSessionState 
{ 
    public MyHttpControllerHandler(RouteData routeData): base(routeData) 
    { } 
} 

public class MyHttpControllerRouteHandler : HttpControllerRouteHandler 
{ 
    protected override IHttpHandler GetHttpHandler(RequestContext requestContext) 
    { 
     return new MyHttpControllerHandler(requestContext.RouteData); 
    } 
} 

public class ValuesController : ApiController 
{ 
    public string GET(string input) 
    { 
     var session = HttpContext.Current.Session; 
     if (session != null) 
     { 
      if (session["Time"] == null) 
      { 
       session["Time"] = DateTime.Now; 
      } 
      return "Session Time: " + session["Time"] + input; 
     } 
     return "Session is not availabe" + input; 
    } 
} 

,然后HttpControllerHandler添加到您的API路线:

route.RouteHandler = new MyHttpControllerRouteHandler(); 
+0

由于已经测试。很有帮助。我不会违反REST,但我想为每个api请求保存数据库行程。我们有唯一的id与api域相关联,这个域需要传递给每个api请求的数据库调用。如果我不使用会话,我最终会为每个api请求重复相同的逻辑。 BTW有没有一种方法可以覆盖类似于我们在asp.net中的PreRequestHandlerExecute,并将数据存储在我想要在每个api请求中检索的会话中? – user1186065 2012-07-16 15:46:22

+4

控制器将很难以这种方式进行单元测试。我将在控制器构造函数中添加一个HttpContextBase(或HttpSessionStateBase)参数,并使用DI将其解析为应用程序的新HttpContextWrapper(HttpContext.Current)。然后在单元测试中,你可以嘲笑它。 – 2012-10-05 19:08:38

+0

正如@Filip所说的,让我们不要按照这个路径(向Web API添加应该是无状态的会话)。但同样的Filip有一篇关于Web API缓存的好文章:http://goo.gl/2rnfI 我在gitHub中分叉了他并为源代码添加了一些功能,现在它支持登录用户的分离输出缓存:http://goo.gl/oW4hX 注意:我仍在改进代码并针对任何可能的安全漏洞进行测试。 – Tohid 2012-12-28 15:26:22

2

如果数据足够小并且不存在安全问题,则可以使用cookie。基于相同的基于HttpContext.Current的方法应该可以工作。

请求和响应HTTP标头也可用于在服务调用之间传递信息。

+0

我知道这是旧的,但可以帮助任何人阅读这些东西。如果您使用XDomainRequest执行CORS ajax请求,那么对于使用IE8/9中的cookie有一个限制。你可以阅读更多关于它[这里](http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx) – elvin 2014-09-15 23:52:03

79

在Global.asax中添加

public override void Init() 
{ 
    this.PostAuthenticateRequest += MvcApplication_PostAuthenticateRequest; 
    base.Init(); 
} 

void MvcApplication_PostAuthenticateRequest(object sender, EventArgs e) 
{ 
    System.Web.HttpContext.Current.SetSessionStateBehavior(
     SessionStateBehavior.Required); 
} 

给它一个镜头;)

+0

这工作!非常感谢你!最佳答案自route.RouteHandler似乎无法正常工作,因为它不是在Web API中的类型。这个答案解决了这个问题。 – Tikkes 2013-04-09 12:13:51

+10

+1我认为如果你知道自己在做什么,可以在某些特殊情况下使用Web API中的Session。 – nima 2013-05-28 12:32:40

+6

我用这个,我的一些网页变得很慢。最好测试请求是否是Web API:if(HttpContext.Current.Request.Url.AbsolutePath.StartsWith(“/ api /”)) – nima 2013-06-01 14:54:04

20

在2的WebAPI,你可以将它添加到Global.asax中

protected void Application_PostAuthorizeRequest() 
{ 
    System.Web.HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required); 
} 

,那么你可以通过以下方式访问会话:

HttpContext.Current.Session 
+3

这是如何在其他答案中添加任何内容的? – 2015-01-21 14:22:48

+0

@eddie_cat简单地说,他把它放在PostAuthorize中。尽管如此,为了使这一点更好,他可以指出并添加条件检查,如果请求是尼玛指出的api请求。 – Suamere 2015-04-29 21:07:27