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
Best Solution
If what you're saying is true and the code execution never reaches your
PostProduct()
action method in yourProductsController
, then the problem must be either earlier in the Web API pipeline (e.g. any global message handlers, filters, etc.) or with the client.It's easy to eliminate the client code from the process by firing the same request and data to your Web API using Fiddler, Postman, etc. I know it's a basic thing to suggest, but since you didn't clarify if you tried this step or not in your question, I had to mention it.
If the request works correctly when sent like that, then it's a problem with your client code. Otherwise, you need to take a look at the code that's executed on your server before your request gets routed to your controller.