【问题标题】:ASP.NET Web API session or something?ASP.NET Web API 会话还是什么?
【发布时间】:2012-07-13 18:17:32
【问题描述】:

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

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

谢谢。

【问题讨论】:

    标签: session asp.net-web-api


    【解决方案1】:

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

    试一试;)

    【讨论】:

    • 这成功了!非常感谢!最佳答案不起作用,因为 route.RouteHandler 似乎不起作用,因为它与 Web API 中的类型不同。这个答案解决了这个问题。
    • +1 如果你知道自己在做什么,我认为在某些特殊情况下使用 Web Api 中的 Session 是可以的。
    • 我用了这个,我的一些页面变得很慢。最好测试一下请求是否是Web API: if (HttpContext.Current.Request.Url.AbsolutePath.StartsWith("/api/"))
    • 如何设置会话超时?
    • @nima 您的评论 [..]("/api")) 中有一些额外的字符:‌​
    【解决方案2】:

    好吧,REST 的设计是无状态的。通过添加会话(或任何其他类型),您将使其成为有状态的,并破坏了拥有 RESTful API 的任何目的。

    RESTful 服务的整体理念是,每个资源都可以使用通用语法进行唯一寻址,以便在超媒体链接中使用,并且每个 HTTP 请求本身都应该携带足够的信息以供其接收者处理它与 HTTP 的无状态特性完全一致”

    因此,无论您在此处尝试使用 Web API 做什么,如果您希望拥有一个 RESTful API,很可能应该重新架构。

    话虽如此,如果你仍然愿意走这条路,有一种将会话添加到 Web API 的 hacky 方法,它已由 Imran 发布在这里 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();
    

    【讨论】:

    • 谢谢。非常有帮助。我不会反对 REST,但我想为每个 api 请求保存数据库之旅。我们有与 api 域相关联的唯一 ID,它发出一个请求,我需要将其传递给每个 api 请求的数据库调用。如果我不使用会话,我最终会为每个 api 请求重复相同的逻辑。顺便说一句,有没有一种方法可以覆盖类似于我们在 asp.net 中的 PreRequestHandlerExecute 并将数据存储在我想在每个 api 请求中检索的会话中?
    • 控制器很难以这种方式进行单元测试。我会在控制器构造函数中添加一个 HttpContextBase(或 HttpSessionStateBase)参数,并使用 DI 将其解析为应用程序的新 HttpContextWrapper(HttpContext.Current)。然后在单元测试中你可以模拟它。
    • 正如@Filip 所说,我们不要走这条路(将会话添加到应该是无状态的Web API)。但是同一个 Filip 有一篇关于 Web API 缓存的好文章:goo.gl/2rnfI 我在 gitHub 中对他进行了 fork,并在源代码中添加了更多功能,现在它支持登录用户的单独输出缓存:goo.gl/oW4hX 注意:我'仍在改进代码并测试任何可能的安全漏洞。
    • 我发现 Web Api 控制器非常有用,因为我可以将模型或视图模型设置为返回类型,并且它可以很好地与我的 javascript 框架配合使用,因此我不必在其中创建 JsonResults普通控制器。从这个意义上说,它们不是真正的无状态 REST API 控制器,而是 AJAX 请求更自然的端点,因此我仍然希望拥有会话状态。
    • 这对 REST 非常有用的地方是,您可以在第一个请求中对用户进行身份验证,然后使用身份验证状态来了解他们在所有后续请求中都经过身份验证。
    【解决方案3】:

    在 WebApi 2 中,您可以将其添加到 global.asax

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

    然后您可以通过以下方式访问会话:

    HttpContext.Current.Session
    

    【讨论】:

    • 这对其他答案有何影响?
    • @eddie_cat 简单地说,他把它放在 PostAuthorize 中。尽管如此,为了使这更好,他可以指出这一点并添加条件检查,如果请求是 api 请求,正如 nima 指出的那样。
    • 这个答案是否会产生对 Web.API 的所有请求进行序列化的效果(即一个长时间运行的方法需要在允许执行下一个方法之前返回)?
    • 不,序列化是全局 asax 上的不同设置。虽然,您的类必须是可序列化的才能存储在会话中
    【解决方案4】:

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

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

    【讨论】:

    • 我知道这是旧的,但可以帮助任何其他阅读这些东西的人。如果您使用 XDomainRequest 执行 CORS ajax 请求,则在 IE8/9 中使用 cookie 存在限制。你可以阅读更多关于它here
    【解决方案5】:

    现在在 2017 年使用 ASP.Net Core,您可以按照此处的说明进行操作。

    Microsoft.AspNetCore.Session 包提供用于管理会话状态的中间件。

    Startup.cs

    public void ConfigureServices(IServiceCollection services)
    {
      // Adds a default in-memory implementation of IDistributedCache.
        services.AddDistributedMemoryCache();
    
        services.AddSession(options =>
        {
            // Set a short timeout for easy testing.
            options.IdleTimeout = TimeSpan.FromSeconds(10);
            options.Cookie.HttpOnly = true;
        });
    }
    
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseSession();
    }
    

    来自文档: Introduction to session and application state in ASP.NET Core

    已经在一个工作项目上测试过

    【讨论】:

      猜你喜欢
      • 2014-11-04
      • 1970-01-01
      • 1970-01-01
      • 2023-03-15
      • 2012-03-24
      • 2015-04-14
      • 2015-02-12
      • 2019-01-29
      • 2016-10-12
      相关资源
      最近更新 更多