ASP.NET HttpResponse Cookies null check - c#

I have a null check in code that is checking to see whether a cookie exists in the response object already:
if (HttpContext.Current.Response.Cookies["CookieName"] != null)
{
sessionCookie = HttpContext.Current.Response.Cookies["CookieName"];
cookieValue = sessionCookie.Value;
}
When I check through the debugger the key doesn't exist before the check, but it does exists after the check. Thus the return value from the cookie is null. Does checking for a cookies existence automatically create the cookie?
Thanks in advance

That case, when the first answer contains a nonsense not related to the question.
Every time when you do the check:
if (HttpContext.Current.Response.Cookies["CookieName"] != null)
this line of code not only checks, whether a cookie exists, but also creates a new empty cookie. Even Get method creates[1] the new cookie implicitly.
You can use the code like this:
Cookie existing_cookie = null;
foreach (Cookie c in HttpContext.Current.Response.Cookies)
{
if ("CookieName" == c.Name)
{
existing_cookie = c;
break;
}
}
if (null != existing_cookie)
{
// exists
}
Or use LINQ methods to do almost the same.

The answer is yes, calling Response.Cookies["CookieName"] in any manner actually creates the cookie.

This happens because HttpContext.Current is associated with the thread that the request is currently executing on. On a different thread, the framework has no way to know which request you want to use.
There are ways to fix this-- for example .NET's BackgroundWorker can propagate context to another thread. The Asynchronous Pages support in ASP.NET will also propagate context correctly.
So you have two options: either rewrite all your async code to use context-passing async mechanisms like BackgroundWorker or Async Pages, or change your code to check for HttpContext.Current==null before trying to access any properties of HttpContext.Current

Related

Cache gets null when I try to retrieve information in another class method

I'm trying to use cache to save some information for later use. This is how I assign cache:
foreach(MibGet Device in DeviceValuesList)
{
if (HttpContext.Current.Cache[DeviceID] == null)
{
HttpContext.Current.Cache[DeviceID] = DeviceValue;
}
}
I can see in the debugger that this code works absolutely fine, all the data I want is assigned properly. But when I try to retrieve this information from the cache like this (From another class method):
if (NewValue != HttpContext.Current.Cache[DeviceID].ToString())
{
HttpContext.Current.Cache[DeviceID] = NewValue;
}
It throws a null reference exception. In the debugger It show that HttpContext.Current is null. What could be the problem and how can I solve this?
HttpContext.Current is null when there is no current HttpContext. ASP.NET uses one thread per request model. It creates an instance of HttpContext and associates it to the thread that process the request. But if you create a thread, explicitly o implicitly by using tasks or async programming, it might not be associated with an HttpContext
I suggest you using some other cache classes such as System.Runtime.Caching.MemoryCache that are not tied to an HttpContext.
I'm assuming your cache is a dictionary. Then instead of
if (get.Value != HttpContext.Current.Cache[get.DeviceID.ToString()].ToString())
you should write
if (!HttpContext.Current.Cache.ContainsKey(get.DeviceID))
Also in your first code snippet you put Device.Value in the cache, but in the second snippet you put DeviceID. I can't see how that'd work.

Handling multiple instances of the same controller

I am currently developing an application in ASP.NET CORE 2.0
The following is the action inside my controller that get's executed when the user clicks submit button.
The following is the function that get's called the action
As a measure to prevent duplicate inside a database I have the function
IsSignedInJob(). The function works
My Problem:
Sometimes when the internet connection is slow or the server is not responding right away it is possible to click submit button more than once. When the connection is reestablished the browser (in my case Chrome) sends multiple HttpPost request to the server. In that case the functions(same function from different instances) are executed so close in time that before the change in database is made, other instances are making the same change without being aware of each other.
Is there a way to solve this problem on a server side without being to "hacky"?
Thank you
As suggested on the comments - and this is my preferred approach-, you can simply disable the button once is clicked the first time.
Another solution would be to add something to a dictionary indicating that the job has already been registered but this will probably have to use a lock as you need to make sure that only one thread can read-write at a time. A Concurrent collection won't do the trick as the problem is not whether this operation is thread-safe or not. The IsSignedInJob method you have can do this behind the scenes but I wouldn't check the database for this as the latency could be too high. Adding/removing a Key from a dictionary should be a lot faster.
Icarus's answer is great for the user experience and should be implemented. If you also need to make sure the request is only handled once on the server side you have a few options. Here is one using the ReaderWRiterLockSlim class.
private ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();
[HttpPost]
public async SomeMethod()
{
if (cacheLock.TryEnterWriteLock(timeout));
{
try
{
// DoWork that should be very fast
}
finally
{
cacheLock.ExitWriteLock();
}
}
}
This will prevent overlapping DoWork code. It does not prevent DoWork from finishing completely, then another post executing that causes DoWork again.
If you want to prevent the post from happening twice, implement the AntiForgeryToken, then store the token in session. Something like this (haven't used session in forever) may not compile, but you should get the idea.
private const SomeMethodTokenName = "SomeMethodToken";
[HttpPost]
public async SomeMethod()
{
if (cacheLock.TryEnterWriteLock(timeout));
{
try
{
var token = Request.Form.Get["__RequestVerificationToken"].ToString();
var session = Session[SomeMethodTokenName ];
if (token == session) return;
session[SomeMethodTokenName] = token
// DoWork that should be very fast
}
finally
{
cacheLock.ExitWriteLock();
}
}
}
Not exactly perfect, two different requests could happen over and over, you could store in session the list of all used tokens for this session. There is no perfect way, because even then, someone could technically cause a OutOfMemoryException if they wanted to (to many tokens stored in session), but you get the idea.
Try not to use asynchronous processing. Remove task,await and async.

Maintaining session in a class C#

I am trying to maintain session in a class for MVC application. Below is the code which i used get and set session in a variable. But whenever i am accessing this variable after set, it is giving null.
public static class MySession
{
public static string MyVar
{
get
{
return HttpContext.Current.Session["MyVar"] == null ? "" : HttpContext.Current.Session["MyVar"].ToString();
}
set
{
HttpContext.Current.Session["MyVar"] = value;
}
}
}
And I used to set as
MySession.MyVar="testData";
But when i access
string str = MySession.MyVar;
it gives null value. Does anybody know why my session is not stored?
Session variables are very much exposed to being null, that is each time a new session is created by user, browser, network or application itself. That is why, it is very much recommended to wrap it around with if...else block.
if(Session["key"] != null) {
// Variable exists for the session
// use variable
} else {
// Variable doesn't exist in the session
// create and user variable
}
However, if still you always get a null, then you should check what is going wrong. My bet is that there is some other code or process that terminates the previous sessions and restarts them. You should know you can programmatically also remove all sessions, that might also cause this problem.
Also, Session variables can be used and served using a class, there is no problem in that. Just make sure that the collection Session isn't being refreshed.
My guess is you have not enabled session state.
<system.web>
<sessionState mode="InProc" timeout="60"/>
<system.web>
Session state is disabled by default in MVC and is generally not recommended unless absolutely necessary.

FormsAuthentication.RedirectToLoginPage() does nothing

I have the following problem: republishing ASP.NET web app causes (as expected) session resetting where I keep additional user info (what on access attempt will cause NullReferenceException).
To avoid that, my page checks this info existence and in case of null redirects user to the login page (forms auth), so I'm calling:
void LogOut()
{
Session.Clear();
Session.Abandon();
User = null;
FormsAuthentication.SignOut();
FormsAuthentication.RedirectToLoginPage()
}
But sometimes it doesn't help, so I found a workaround:
Response.Redirect(FormsAuthentication.LoginUrl);
but it doesn't add returnUrl, what I wish it were (I don't want to emulate this behavior manually).
So want to figure out why does the first way doesn't work as expected.
Have you tried calling Response.End() after FormsAuthentication.RedirectToLoginPage() ?
I have the following problem: republishing ASP.NET web app causes (as expected) session resetting where I keep additional user info (what on access attempt will cause NullReferenceException).
But sometimes it doesn't help
I'm not sure what you mean by "sometimes it doesn't help" - you don't say what exactly happens.
But you should remember that expiration of a Forms Authentication ticket and expiration of a Session timeout are completely independent. A user's session can timeout while his Forms Authentication ticket is still valid and vice versa.
In general, when accessing data from Session, you should always test for existence first, and refresh it if necessary:
object o = Session["Whatever"];
if (o == null)
{
o = ... refresh it e.g. from the database
Session["Whatever"] = o;
}
...
Often it's useful to use a helper class to encapsulate this.
In your case you refer to "additional user info" - so you'll probably be able to retrieve this using HttpContext.Current.User.Identity.Name as a key.
Forcing a user to log in again because a Session has expired, e.g. because of an Application Pool recycle on the server, is very unfriendly.
UPDATE
The MSDN documentation for RedirectToLoginPage states that:
Unlike the HttpResponse.Redirect method, this method does not end the request by calling HttpResponse.End. This means that code that follows the RedirectToLoginPage method call will run.
This probably explains what you're seeing: code in the Page life cycle after your call to RedirectToLoginPage is running, and throwing a NullReferenceException.
You could call Response.End after RedirectToLoginPage to avoid this.
My Session timeout set = Forms auth timeout (via web.config).
I would re-iterate that Session expiry and FormsAuthentication expiry are unrelated, even if the timeouts happen to be the same. A FormsAuthentication cookie will survive an application pool recycle on the server; a Session will not.

is it better to test if a function is needed inside or outside of it?

what is the best practice? call a function then return if you test for something, or test for something then call?
i prefer the test inside of function because it makes an easier viewing of what functions are called.
for example:
protected void Application_BeginRequest(object sender, EventArgs e)
{
this.FixURLCosmetics();
}
and
private void FixURLCosmetics()
{
HttpContext context = HttpContext.Current;
if (!context.Request.HttpMethod.ToString().Equals("GET", StringComparison.OrdinalIgnoreCase))
{
// if not a GET method cancel url cosmetics
return;
};
string url = context.Request.RawUrl.ToString();
bool doRedirect = false;
// remove > default.aspx
if (url.EndsWith("/default.aspx", StringComparison.OrdinalIgnoreCase))
{
url = url.Substring(0, url.Length - 12);
doRedirect = true;
}
// remove > www
if (url.Contains("//www"))
{
url = url.Replace("//www", "//");
doRedirect = true;
}
// redirect if necessary
if (doRedirect)
{
context.Response.Redirect(url);
}
}
is this good:
if (!context.Request.HttpMethod.ToString().Equals("GET", StringComparison.OrdinalIgnoreCase))
{
// if not a GET method cancel url cosmetics
return;
};
or should that test be done in Application_BeginRequest?
what is better?
thnx
I feel like testing inside the function is better. If you test outside of the function, you'll have to test everywhere that function could be called (and would cause a lot of duplicate code).
It's nicer to have everything in one place then spread out everywhere.
If a method absolutely requires a certain condition to be met before it can perform its function then yes, you should put the validation inside that function. If, on the other hand, your calling code is saying "only perform this operation under this set of conditions" then the condition is better in the calling code, because next time you want to call that method you may not want to include that condition.
In this case, I feel that the name of the function implies that something is going to happen to the URL in every case. Someone may want to call FixURLCosmetics on a non-GET page and expect something to happen.
I would rename FixURLCosmetics to FixGETURLCosmetics. Then, throw an exception if it's called on a non-GET page.
If I were you i would test in BOTH places, being outside AND inside, and mocking the inner components that are being called (such as context.Request calls), to strengthen also the inner behavior and also mocking some unexpected returns and how your method deals with them.
In this case, an API such as easymock could simplifty A LOT the mocking of inner components.

Categories

Resources