我知道会话和REST并不完全是齐头并进的,但是使用新的Web API访问会话状态是不可能的吗?session总是空的。


当前回答

您可以使用自定义RouteHandler访问会话状态。

// In global.asax
public class MvcApp : System.Web.HttpApplication
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        var route = routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
        route.RouteHandler = new MyHttpControllerRouteHandler();
    }
}

// Create two new classes
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);
    }
}

// Now Session is visible in your Web API
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;
    }
}

在这里找到:http://techhasnoboundary.blogspot.com/2012/03/mvc-4-web-api-access-session.html

其他回答

我在asp.net mvc中也有同样的问题,我把这个方法放在我的基础api控制器中,我所有的api控制器都继承了这个方法:

    /// <summary>
    /// Get the session from HttpContext.Current, if that is null try to get it from the Request properties.
    /// </summary>
    /// <returns></returns>
    protected HttpContextWrapper GetHttpContextWrapper()
    {
      HttpContextWrapper httpContextWrapper = null;
      if (HttpContext.Current != null)
      {
        httpContextWrapper = new HttpContextWrapper(HttpContext.Current);
      }
      else if (Request.Properties.ContainsKey("MS_HttpContext"))
      {
        httpContextWrapper = (HttpContextWrapper)Request.Properties["MS_HttpContext"];
      }
      return httpContextWrapper;
    }

然后在你想要访问会话的api调用中,你只需要做:

HttpContextWrapper httpContextWrapper = GetHttpContextWrapper();
var someVariableFromSession = httpContextWrapper.Session["SomeSessionValue"];

我在我的Global.asax.cs文件中也有这个,就像其他人发布的一样,不确定你是否仍然需要使用上面的方法,但这里只是以防万一:

/// <summary>
/// The following method makes Session available.
/// </summary>
protected void Application_PostAuthorizeRequest()
{
  if (HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.StartsWith("~/api"))
  {
    HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
  }
}

你也可以只做一个自定义过滤器属性,你可以粘在你的api调用,你需要会话,然后你可以在你的api调用中使用会话,就像你通常会通过HttpContext.Current.Session["SomeValue"]:

  /// <summary>
  /// Filter that gets session context from request if HttpContext.Current is null.
  /// </summary>
  public class RequireSessionAttribute : ActionFilterAttribute
  {
    /// <summary>
    /// Runs before action
    /// </summary>
    /// <param name="actionContext"></param>
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
      if (HttpContext.Current == null)
      {
        if (actionContext.Request.Properties.ContainsKey("MS_HttpContext"))
        {
          HttpContext.Current = ((HttpContextWrapper)actionContext.Request.Properties["MS_HttpContext"]).ApplicationInstance.Context;
        }
      }
    }
  }

希望这能有所帮助。

@LachlanB的回答中有一件事需要提一下。

protected void Application_PostAuthorizeRequest()
    {
        if (IsWebApiRequest())
        {
            HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
        }
    }

如果省略了If (IsWebApiRequest())

如果你的网站混合了网页表单,整个网站都会有页面加载缓慢的问题。

回到基础,为什么不保持它的简单和存储会话值在一个隐藏的html值传递给你的API?

控制器

public ActionResult Index()
        {

            Session["Blah"] = 609;

            YourObject yourObject = new YourObject();
            yourObject.SessionValue = int.Parse(Session["Blah"].ToString());

            return View(yourObject);
        }

cshtml

@model YourObject

@{
    var sessionValue = Model.SessionValue;
}

<input type="hidden" value="@sessionValue" id="hBlah" />

Javascript

$(文件)。准备(函数(){

    var sessionValue = $('#hBlah').val();

    alert(sessionValue);

    /* Now call your API with the session variable */}

}

您可以使用自定义RouteHandler访问会话状态。

// In global.asax
public class MvcApp : System.Web.HttpApplication
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        var route = routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
        route.RouteHandler = new MyHttpControllerRouteHandler();
    }
}

// Create two new classes
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);
    }
}

// Now Session is visible in your Web API
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;
    }
}

在这里找到:http://techhasnoboundary.blogspot.com/2012/03/mvc-4-web-api-access-session.html

你说得对,REST是无状态的。如果您使用会话,处理将变成有状态的,后续请求将能够使用状态(来自会话)。

为了给会话补水,您需要提供一个键来关联状态。在普通的asp.net应用程序中,该密钥是通过使用cookie (cookie-sessions)或url参数(无cookie会话)来提供的。

如果你需要一个会话而不是休息,那么会话在基于rest的设计中是无关紧要的。如果您需要一个会话进行验证,则使用令牌或通过IP地址授权。