Accessing Session Using ASP.NET Web API

You can access session state using a custom 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;
    }
}

Found here: http://techhasnoboundary.blogspot.com/2012/03/mvc-4-web-api-access-session.html


MVC

For an MVC project make the following changes (WebForms and Dot Net Core answer down below):

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

}

This solution has the added bonus that we can fetch the base URL in javascript for making the AJAX calls:

_Layout.cshtml

<body>
    @RenderBody()

    <script type="text/javascript">
        var apiBaseUrl = '@Url.Content(ProjectNameSpace.WebApiConfig.UrlPrefixRelative)';
    </script>

    @RenderSection("scripts", required: false) 

and then within our Javascript files/code we can make our webapi calls that can access the session:

$.getJSON(apiBaseUrl + '/MyApi')
   .done(function (data) {
       alert('session data received: ' + data.whatever);
   })
);

WebForms

Do the above but change the WebApiConfig.Register function to take a RouteCollection instead:

public static void Register(RouteCollection routes)
{
    routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: WebApiConfig.UrlPrefix + "/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
}

And then call the following in Application_Start:

WebApiConfig.Register(RouteTable.Routes);

Dot Net Core

Add the Microsoft.AspNetCore.Session NuGet package and then make the following code changes:

Startup.cs

Call the AddDistributedMemoryCache and AddSession methods on the services object within the ConfigureServices function:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    ...

    services.AddDistributedMemoryCache();
    services.AddSession();

and in the Configure function add a call to UseSession:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, 
ILoggerFactory loggerFactory)
{
    app.UseSession();
    app.UseMvc();

SessionController.cs

Within your controller, add a using statement at the top:

using Microsoft.AspNetCore.Http;

and then use the HttpContext.Session object within your code like so:

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

you should now be able to hit:

http://localhost:1234/api/session/set/thisissomedata

and then going to this URL will pull it out:

http://localhost:1234/api/session/get

Plenty more info on accessing session data within dot net core here: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/app-state

Performance Concerns

Read Simon Weaver's answer below regarding performance. If you're accessing session data inside a WebApi project it can have very serious performance consequence - I have seen ASP.NET enforce a 200ms delay for concurrent requests. This could add up and become disastrous if you have many concurrent requests.


Security Concerns

Make sure you are locking down resources per user - an authenticated user shouldn't be able to retrieve data from your WebApi that they don't have access to.

Read Microsoft's article on Authentication and Authorization in ASP.NET Web API - https://www.asp.net/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api

Read Microsoft's article on avoiding Cross-Site Request Forgery hack attacks. (In short, check out the AntiForgery.Validate method) - https://www.asp.net/web-api/overview/security/preventing-cross-site-request-forgery-csrf-attacks