Reputation: 3640
If you have the following code in a (non Core) ASP.NET MVC 5 project:
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Mvc;
namespace ASPApp.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public Task<ActionResult> UnSafeThreadAccess()
{
PrintThreadId("UnSafeThreadAccess entry");
var synchronisationContext = SynchronizationContext.Current;
return Task.Delay(2).ContinueWith(_ =>
{
PrintThreadId("UnSafeThreadAccess continueWith");
var controllerContext = HttpContext.Request.QueryString["q"];
var content = $"Responding to {System.Web.HttpContext.Current.Request.QueryString["q"]}";
return Content(content) as ActionResult;
});
}
private static void PrintThreadId(string threadName)
{
Trace.WriteLine($"{threadName}: {Thread.CurrentThread.ManagedThreadId}");
}
}
}
I knew that accessing System.Web.HttpContext.Current
inside the ContinueWith
is bad, since it is bound to the entry thread of the controller. The point of this code is to illustrate why awaiting the Task.Delay
is necessary in this example.
However I was a bit surprised that the HttpContext
property of the controller can be accessed inside ContinueWith
. How is this possible? I know the type of the property is not HttpContext
but HttpContextBase
, however I was expecting that this would just call through to the static HttpContext instance.
Upvotes: 0
Views: 803
Reputation: 2970
However I was a bit surprised that the
HttpContext
property of the controller can be accessed insideContinueWith
. How is this possible? [...], however I was expecting that this would just call through to the staticHttpContext
instance.
Digging in the sources reveals that Controller.HttpContext
is not a plain call-through to HttpContext.Current
but HTTP context is retrieved from the request context ( System.Web.Routing.RequestContext
) which actually stores a reference to the current HttpContextBase
instance:
https://github.com/aspnet/AspNetWebStack/blob/v3.2.6/src/System.Web.Mvc/Controller.cs#L87
https://github.com/aspnet/AspNetWebStack/blob/v3.2.6/src/System.Web.Mvc/ControllerContext.cs#L71
https://github.com/Microsoft/referencesource/blob/4.6.2/System.Web/Routing/RequestContext.cs#L23
In this sense it's safe to access Controller.HttpContext
from another thread than the entry thread of the request.
However, MSDN says the following about HttpContext
:
This object is ready for garbage collection when the HttpRequest is completed. Its usage after the request completes could lead to undefined behavior, such as a NullReferenceException.
This object is only available in the thread controlled by ASP.NET. Usage in background threads could lead to undefined behavior.
This is not the most precise piece of phrasing but I assume that at least operations that don't mutate the state of the object (like reading the request query string) must be safe in background threads. (Before the request completes, of course.)
Upvotes: 1