Why is HttpContext.Current null?
Clearly HttpContext.Current
is not null
only if you access it in a thread that handles incoming requests. That's why it works "when i use this code in another class of a page".
It won't work in the scheduling related class because relevant code is not executed on a valid thread, but a background thread, which has no HTTP context associated with.
Overall, don't use Application["Setting"]
to store global stuffs, as they are not global as you discovered.
If you need to pass certain information down to business logic layer, pass as arguments to the related methods. Don't let your business logic layer access things like HttpContext
or Application["Settings"]
, as that violates the principles of isolation and decoupling.
Update:
Due to the introduction of async/await
it is more often that such issues happen, so you might consider the following tip,
In general, you should only call HttpContext.Current
in only a few scenarios (within an HTTP module for example). In all other cases, you should use
Page.Context
https://learn.microsoft.com/en-us/dotnet/api/system.web.ui.page.context?view=netframework-4.7.2Controller.HttpContext
https://learn.microsoft.com/en-us/dotnet/api/system.web.mvc.controller.httpcontext?view=aspnet-mvc-5.2
instead of HttpContext.Current
.
Why HttpContext is null?
System.Web.HttpContext.Current
is populated by IIS which is not present/active during unit testing. Hence null. Do not tightly couple your code to HttpContext
for that very reason. Instead encapsulate that behind abstractions that can be mocked when testing in isolation.
Bad design aside, for your specific design you are trying to access a static dependency external to the controller. If faking the controller's context as demonstrated in your current test, then access the controller's context instead of calling the static context.
//... code removed for brevity
var _authProvider = new AuthenticationProvider(this.HttpContext);
//... code removed for brevity
With that out of the way, the design of the controller should be refactored to explicitly depend on abstractions instead of concretions.
for example, here is an abstraction for the provider
public interface IAuthenticationProvider : IFormsAuthentication {
void CheckAuthorizationForUrl(string url);
//...other members
}
public class AuthenticationProvider : IAuthenticationProvider {
//...
}
The controller should explicitly depend on this via constructor injection
public class HomeController : Controller {
private readonly IAuthenticationProvider authProvider;
public HomeController(IAuthenticationProvider authProvider) {
this.authProvider = authProvider;
}
public ActionResult Index() {
ViewBag.Title = "Home Page";
var guidAccount = "xxxxxxxx-xxxx-xxxx-xxxx-422632e0bd95";
var userData = new CookieUserData(guidAccount) { GuidAccount = guidAccount };
authProvider.CheckAuthorizationForUrl("http://pippo");
return View();
}
}
The IAuthenticationProvider
implementation should be configured to be injected into the controller at run time using the framework's DependencyResolver
if using dependency injection, but can now be replaced when testing the controller in isolation so as not to be coupled to framework implementation concerns.
[TestClass]
public class HomeControllerTest {
[TestMethod]
public void Index(){
// Disposizione
var authMock = new Mock<IAuthenticationProvider>();
var controller = new HomeController(authMock.Object);
// Azione
ViewResult result = controller.Index() as ViewResult;
// Asserzione
Assert.IsNotNull(result);
Assert.AreEqual("Home Page", result.ViewBag.Title);
}
}
Why is HttpContext.Current null after await?
Please ensure you are writing an ASP.NET 4.5 application, and targeting 4.5. async
and await
have undefined behavior on ASP.NET unless you are running on 4.5 and are using the new "task-friendly" synchronization context.
In particular, this means you must either:
- Set
httpRuntime.targetFramework
to4.5
, or - In your
appSettings
, setaspnet:UseTaskFriendlySynchronizationContext
totrue
.
More information is available here.
System.Web.HttpContext.Current.get returned null in asp.net mvc controller
The System.Web
namespace is not used in ASP.NET Core MVC, hence System.Web.HttpContext.Current
property will always return null value (note that HttpContext
is injected). If you want to set session variable in IActionResult
controller, you can use SessionExtensions.SetString
method:
string key = "cart";
HttpContext.Session.SetString(key, jsoncart);
If you want to retrieve it, use SessionExtensions.GetString
method:
string jsonCart = HttpContext.Session.GetString("cart");
Note: To get HttpContext
instance work, put using Microsoft.AspNetCore.Http;
before namespace declaration.
Further reference: Session and app state in ASP.NET Core
HTTPContext.Current in controller is null after multiple awaits
In blogs msdn there is a full research regarding this issue and a mapping of the problem, I.E to the root of the trouble:
The HttpContext object stores all the request-relevant data, including
the pointers to the native IIS request object, the ASP.NET pipeline
instance, the Request and Response properties, the Session (and many
others). Without all of this information, we can safely tell our code
is unaware of the request context it is executing into. Designing
entirely stateless web applications is not easy and implementing them
is indeed a challenging task. Moreover, web applications are rich of
third party libraries, which are generally black boxes where
unspecified code runs.
It is a very interesting thing to ponder about, how such a crucial and fundamental object in the program, HttpContext
is lost during the request execution.
The soultion provided:
It consists of TaskScheduler
, the ExecutionContext
and the SynchronizationContext
:
- The
TaskScheduler
is exactly what you would expect. A scheduler for tasks! (I would be a great teacher!) Depending on the type of .NET
application used, a specific task scheduler might be better than
others. ASP.NET uses the ThreadPoolTaskScheduler by default, which is
optimized for throughput and parallel background processing.- The
ExecutionContext
(EC) is again somehow similar to what the name suggests. You can look at it as a substitute of the TLS (thread local
storage) for multithreaded parallel execution. In extreme synthesis,
it is the object used to persist all the environmental context needed
for the code to run and it guarantees that a method can be
interrupted and resumed on different threads without harm (both from
a logical and security perspective). The key aspect to understand is
the EC needs to "flow" (essentially, be copied over from a thread to
another) whenever a code interrupt/resume occurs.- The
SynchronizationContext
(SC) is instead somewhat more difficult to grasp. It is related and in some ways similar to the EC, albeit
enforcing a higher layer of abstraction. Indeed it can persist
environmental state, but it has dedicated implementations for
queueing/dequeuing work items in specific environments. Thanks to the
SC, a developer can write code without bothering about how the
runtime handles the async/await patterns.
If you consider the code from the blog's example:
await DoStuff(doSleep, configAwait)
.ConfigureAwait(configAwait);
await Task.Factory.StartNew(
async () => await DoStuff(doSleep, configAwait)
.ConfigureAwait(configAwait),
System.Threading.CancellationToken.None,
asyncContinue ? TaskCreationOptions.RunContinuationsAsynchronously : TaskCreationOptions.None,
tsFromSyncContext ? TaskScheduler.FromCurrentSynchronizationContext() : TaskScheduler.Current)
.Unwrap().ConfigureAwait(configAwait);
The explenation:
configAwait
: controls the ConfigureAwait behavior when awaiting tasks (read on for additional considerations)tsFromSyncContext
: controls the TaskScheduler option passed to the StartNew method. If true, the TaskScheduler is built from the current
SynchronizationContext, otherwise the Current TaskScheduler is used.doSleep
: if True, DoStuff awaits on a Thread.Sleep. If False, it awaits on a HttpClient.GetAsync operation Useful if you want to test
it without internet connectionasyncContinue
: controls the TaskCreationOptions passed to the StartNew method. If true, the continuations are run asynchronously.
Useful if you plan to test continuation tasks too and to assess the
behavior of task inlining in case of nested awaiting operations
(doesn't affect LegacyASPNETSynchronizationContext)
Dive into the article and see if it matches your issue, I believe you will find useful info inside.
There is another solution here, using nested container, you can check it as well.
Why is HttpContext.Current null during the Session_End event?
On Session_End there is no communication necessarily involved with the browser so there is no HttpContext to refer to which explains why it is null.
Looking at your code you seem to be intersted in the Application cache. That is available via Application property on the HttpApplication instance.
If you create an overload on your UserCount class that takes an HttpApplicationState you'll be fine:
public static void subtract(HttpApplicationState appstate)
{
appstate.Lock();
int count = (int) appstate["CountOfUsers"];
count--;
appstate["CountOfUsers"]=count;
appstate.UnLock();
}
You can use this from Session_End like so:
protected void Session_End(object sender, EventArgs e)
{
UserCount.subtract(Application);
}
This works because global_asax is technically an subclass from HttpApplication and so all its members are accessible from the global_asax file.
The other implementation of substract
can be used when there is an HttpContext.
HttpContext.Current is null in my web service
If you want to use HttpContext
because the code has already been written as so; you need to add this to your web.config where your service resides:
<configuration>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
</configuration>
HttpContext.Current is null when using IAuthenticationFilter
The solution was to include "targetFramework=4.5" in the web.config as commented by @Alfredo and more details in https://stackoverflow.com/a/32338414/3973463
Related Topics
Datetime Conversion from String C#
How to Make the Value of a Variable Track the Value of Another
How to Change the Background Color of All Other Forms from One Form
Repository Pattern Step by Step Explanation
What Is the Fastest Way to Create a Checksum for Large Files in C#
How to Run and Interact with an Async Task from a Wpf Gui
Identityserver4 Register Userservice and Get Users from Database in ASP.NET Core
Dynamic Routes from Database for ASP.NET MVC Cms
How to Initialize a C# Dictionary with Values
How to Get the Full Url of the Page I am on in C#
What's the Best Way to Pass Event to Viewmodel
Call a Method from Another Form
C# When Should I Use List and When Should I Use Arraylist
How to Call a Variable in Code Behind to Aspx Page