Acceso a la sesión mediante la API web ASP.NET
Me doy cuenta de que la sesión y el REST no van exactamente de la mano, pero ¿no es posible acceder al estado de la sesión utilizando la nueva API web? HttpContext.Current.Session
siempre es nulo.
mvc
Para un proyecto MVC, realice los siguientes cambios (WebForms y Dot Net Core responden a continuación):
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);
}
}
Esta solución tiene la ventaja adicional de que podemos recuperar la URL base en javascript para realizar las llamadas AJAX:
_Diseño.cshtml
<body>
@RenderBody()
<script type="text/javascript">
var apiBaseUrl = '@Url.Content(ProjectNameSpace.WebApiConfig.UrlPrefixRelative)';
</script>
@RenderSection("scripts", required: false)
y luego dentro de nuestros archivos/código Javascript podemos realizar nuestras llamadas webapi que pueden acceder a la sesión:
$.getJSON(apiBaseUrl + '/MyApi')
.done(function (data) {
alert('session data received: ' + data.whatever);
})
);
Formularios web
Haga lo anterior pero cambie la función WebApiConfig.Register para tomar una RouteCollection en su lugar:
public static void Register(RouteCollection routes)
{
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: WebApiConfig.UrlPrefix + "/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
Y luego llame a lo siguiente en Application_Start:
WebApiConfig.Register(RouteTable.Routes);
Núcleo de red de puntos
Agregue el paquete Microsoft.AspNetCore.Session NuGet y luego realice los siguientes cambios de código:
Inicio.cs
Llame a los métodos AddDistributedMemoryCache y AddSession en el objeto de servicios dentro de la función ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
...
services.AddDistributedMemoryCache();
services.AddSession();
y en la función Configurar agregue una llamada a UseSession :
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
app.UseSession();
app.UseMvc();
Controlador de sesión.cs
Dentro de su controlador, agregue una declaración de uso en la parte superior:
using Microsoft.AspNetCore.Http;
y luego use el objeto HttpContext.Session dentro de su código de esta manera:
[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);
}
ahora deberías poder presionar:
http://localhost:1234/api/session/set/thisissomedata
y luego, al ir a esta URL, lo extraerá:
http://localhost:1234/api/session/get
Mucha más información sobre cómo acceder a los datos de la sesión dentro de dot net core aquí: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/app-state
Preocupaciones sobre el rendimiento
Lea la respuesta de Simon Weaver a continuación sobre el rendimiento. Si accede a datos de sesión dentro de un proyecto WebApi, puede tener consecuencias de rendimiento muy graves: he visto a ASP.NET imponer un retraso de 200 ms para solicitudes simultáneas. Esto podría acumularse y volverse desastroso si tiene muchas solicitudes simultáneas.
Preocupaciones de seguridad
Asegúrese de bloquear recursos por usuario: un usuario autenticado no debería poder recuperar datos de su WebApi a los que no tiene acceso.
Lea el artículo de Microsoft sobre autenticación y autorización en ASP.NET Web API: https://www.asp.net/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api
Lea el artículo de Microsoft sobre cómo evitar ataques de piratería de falsificación de solicitudes entre sitios. (En resumen, consulte el método AntiForgery.Validate): https://www.asp.net/web-api/overview/security/preventing-cross-site-request-forgery-csrf-attacks
Puede acceder al estado de la sesión utilizando un RouteHandler personalizado.
// 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;
}
}
Encontrado aquí: http://techhasnoboundary.blogspot.com/2012/03/mvc-4-web-api-access-session.html
¿Por qué evitar el uso de Session en WebAPI?
¡Rendimiento, desempeño, desempeño!
Hay una razón muy buena, y a menudo pasada por alto, por la que no debería utilizar Session en WebAPI en absoluto.
La forma en que funciona ASP.NET cuando se utiliza Session es serializar todas las solicitudes recibidas de un único cliente . Ahora no me refiero a la serialización de objetos, sino a ejecutarlos en el orden recibido y esperar a que se complete cada uno antes de ejecutar el siguiente. Esto es para evitar condiciones desagradables de hilo/carrera si dos solicitudes intentan acceder a la sesión simultáneamente.
Solicitudes simultáneas y estado de sesión
El acceso al estado de sesión de ASP.NET es exclusivo por sesión, lo que significa que si dos usuarios diferentes realizan solicitudes simultáneas, el acceso a cada sesión separada se otorga simultáneamente. Sin embargo, si se realizan dos solicitudes simultáneas para la misma sesión (utilizando el mismo valor de SessionID), la primera solicitud obtiene acceso exclusivo a la información de la sesión. La segunda solicitud se ejecuta solo después de que finaliza la primera solicitud. (La segunda sesión también puede obtener acceso si se libera el bloqueo exclusivo de la información porque la primera solicitud excede el tiempo de espera de bloqueo). Si el valor EnableSessionState en la directiva @ Page está establecido en ReadOnly, una solicitud de solo lectura La información de la sesión no da como resultado un bloqueo exclusivo de los datos de la sesión. Sin embargo, es posible que las solicitudes de solo lectura de datos de sesión aún tengan que esperar a que se borre un bloqueo establecido por una solicitud de lectura y escritura para datos de sesión.
Entonces, ¿qué significa esto para la API web? Si tiene una aplicación que ejecuta muchas solicitudes AJAX, solo UNA podrá ejecutarse a la vez. Si tiene una solicitud más lenta, bloqueará todas las demás de ese cliente hasta que se complete. En algunas aplicaciones, esto podría provocar un rendimiento notablemente lento.
Por lo tanto, probablemente debería usar un controlador MVC si es absolutamente necesario algo de la sesión de los usuarios y evitar la penalización de rendimiento innecesaria de habilitarlo para WebApi.
Puede probar esto fácilmente usted mismo simplemente instalando Thread.Sleep(5000)
un método WebAPI y habilitando la sesión. Ejecute 5 solicitudes y tardarán un total de 25 segundos en completarse. Sin Session tardarán un total de poco más de 5 segundos.
(Este mismo razonamiento se aplica a SignalR).