我知道会话和REST并不完全是齐头并进的,但是使用新的Web API访问会话状态是不可能的吗?session总是空的。
当前回答
MVC
对于MVC项目进行以下更改(WebForms和Dot Net Core的答案在下面):
WebApiConfig.cs
public static class WebApiConfig
{
public static string UrlPrefix { get { return "api"; } }
public static string UrlPrefixRelative { get { return "~/api"; } }
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: WebApiConfig.UrlPrefix + "/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Global.asax.cs
public class MvcApplication : System.Web.HttpApplication
{
...
protected void Application_PostAuthorizeRequest()
{
if (IsWebApiRequest())
{
HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
}
}
private bool IsWebApiRequest()
{
return HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.StartsWith(WebApiConfig.UrlPrefixRelative);
}
}
这个解决方案有额外的好处,我们可以在javascript中获取基本URL来进行AJAX调用:
_Layout.cshtml
<body>
@RenderBody()
<script type="text/javascript">
var apiBaseUrl = '@Url.Content(ProjectNameSpace.WebApiConfig.UrlPrefixRelative)';
</script>
@RenderSection("scripts", required: false)
然后在我们的Javascript文件/代码,我们可以使我们的webapi调用,可以访问会话:
$.getJSON(apiBaseUrl + '/MyApi')
.done(function (data) {
alert('session data received: ' + data.whatever);
})
);
网络表单
执行上述操作,但更改WebApiConfig。寄存器函数来代替一个RouteCollection:
public static void Register(RouteCollection routes)
{
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: WebApiConfig.UrlPrefix + "/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
然后在Application_Start中调用以下命令:
WebApiConfig.Register(RouteTable.Routes);
网点核心
添加Microsoft.AspNetCore.Session NuGet包,然后进行以下代码更改:
Startup.cs
在ConfigureServices函数的服务对象上调用AddDistributedMemoryCache和AddSession方法:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
...
services.AddDistributedMemoryCache();
services.AddSession();
在Configure函数中添加一个对UseSession的调用:
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
app.UseSession();
app.UseMvc();
SessionController.cs
在你的控制器中,在顶部添加一个using语句:
using Microsoft.AspNetCore.Http;
然后使用HttpContext。会话对象在你的代码中,如下所示:
[HttpGet("set/{data}")]
public IActionResult setsession(string data)
{
HttpContext.Session.SetString("keyname", data);
return Ok("session data set");
}
[HttpGet("get")]
public IActionResult getsessiondata()
{
var sessionData = HttpContext.Session.GetString("keyname");
return Ok(sessionData);
}
你现在应该可以点击:
http://localhost:1234/api/session/set/thisissomedata
然后转到这个URL会把它拉出来:
http://localhost:1234/api/session/get
更多关于在。net core中访问会话数据的信息请访问:https://learn.microsoft.com/en-us/aspnet/core/fundamentals/app-state
性能问题
下面是西蒙·韦弗关于性能的回答。如果你在WebApi项目中访问会话数据,可能会有非常严重的性能后果。NET对并发请求强制执行200ms延迟。如果您有许多并发请求,这可能会导致灾难性的后果。
安全问题
确保你为每个用户锁定了资源——一个经过身份验证的用户不应该能够从你的WebApi中检索他们没有权限访问的数据。
阅读微软关于ASP中的身份验证和授权的文章。NET Web API - https://www.asp.net/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api
阅读微软关于避免跨站点请求伪造黑客攻击的文章。(简而言之,看看AntiForgery。验证方法)- https://www.asp.net/web-api/overview/security/preventing-cross-site-request-forgery-csrf-attacks
其他回答
我采用了@LachlanB方法,当请求上有会话cookie时,会话确实是可用的。缺失的部分是会话cookie是如何第一次发送到客户端?
我创建了一个HttpModule,它不仅启用httpessionstate可用性,而且还在创建新会话时向客户端发送cookie。
public class WebApiSessionModule : IHttpModule
{
private static readonly string SessionStateCookieName = "ASP.NET_SessionId";
public void Init(HttpApplication context)
{
context.PostAuthorizeRequest += this.OnPostAuthorizeRequest;
context.PostRequestHandlerExecute += this.PostRequestHandlerExecute;
}
public void Dispose()
{
}
protected virtual void OnPostAuthorizeRequest(object sender, EventArgs e)
{
HttpContext context = HttpContext.Current;
if (this.IsWebApiRequest(context))
{
context.SetSessionStateBehavior(SessionStateBehavior.Required);
}
}
protected virtual void PostRequestHandlerExecute(object sender, EventArgs e)
{
HttpContext context = HttpContext.Current;
if (this.IsWebApiRequest(context))
{
this.AddSessionCookieToResponseIfNeeded(context);
}
}
protected virtual void AddSessionCookieToResponseIfNeeded(HttpContext context)
{
HttpSessionState session = context.Session;
if (session == null)
{
// session not available
return;
}
if (!session.IsNewSession)
{
// it's safe to assume that the cookie was
// received as part of the request so there is
// no need to set it
return;
}
string cookieName = GetSessionCookieName();
HttpCookie cookie = context.Response.Cookies[cookieName];
if (cookie == null || cookie.Value != session.SessionID)
{
context.Response.Cookies.Remove(cookieName);
context.Response.Cookies.Add(new HttpCookie(cookieName, session.SessionID));
}
}
protected virtual string GetSessionCookieName()
{
var sessionStateSection = (SessionStateSection)ConfigurationManager.GetSection("system.web/sessionState");
return sessionStateSection != null && !string.IsNullOrWhiteSpace(sessionStateSection.CookieName) ? sessionStateSection.CookieName : SessionStateCookieName;
}
protected virtual bool IsWebApiRequest(HttpContext context)
{
string requestPath = context.Request.AppRelativeCurrentExecutionFilePath;
if (requestPath == null)
{
return false;
}
return requestPath.StartsWith(WebApiConfig.UrlPrefixRelative, StringComparison.InvariantCultureIgnoreCase);
}
}
回到基础,为什么不保持它的简单和存储会话值在一个隐藏的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 */}
}
根据LachlanB的回答,如果你的ApiController不在特定的目录(比如/api)中,你可以使用RouteTable.Routes来测试请求。GetRouteData,例如:
protected void Application_PostAuthorizeRequest()
{
// WebApi SessionState
var routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(HttpContext.Current));
if (routeData != null && routeData.RouteHandler is HttpControllerRouteHandler)
HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
}
是的,会话与Rest API并不是紧密相连的,而且我们应该避免这种做法。但是根据需求,我们需要以某种方式维护会话,以便在每个请求中客户端服务器可以交换或维护状态或数据。因此,在不破坏REST协议的情况下实现这一点的最佳方法是通过JWT这样的令牌进行通信。
https://jwt.io/
要解决这个问题:
protected void Application_PostAuthorizeRequest()
{
System.Web.HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required);
}
在Global.asax.cs
推荐文章
- 什么是Kestrel (vs IIS / Express)
- 如何为ASP.net/C#应用程序配置文件值中的值添加&号
- 我如何解决“HTTP错误500.19 -内部服务器错误”在IIS7.0
- 可选查询字符串参数。NET Web API
- 将列表序列化为JSON
- 运行计划任务的最佳方式
- Global.asax中的“解析器错误消息:无法加载类型”
- 什么时候我应该在ASP中使用异步控制器。净MVC吗?
- ASP。NET“特殊”标签
- 如何编辑。csproj文件
- 如何使用网络强制HTTPS。配置文件
- 如何在WebAPI上使用Swashbuckle省略Swagger文档中的方法
- 无法加载.ps1,因为在此系统上禁止执行脚本
- 找不到如何使用HttpContent
- 我如何循环通过日期范围?