MVC Session SQLServer doesn't allow updates - c#

I have a fairly basic MVC4 website. I'm using SQL Server sessions like so:
<sessionState
mode="SQLServer" regenerateExpiredSessionId="true" timeout="1440"
sqlConnectionString="Password=pass; Persist Security Info=True; User ID=user; Data Source=server;"
/>
When a user logs in, I add an item to the session like so:
Session["test"] = 3;
That works fine, the issue arises when I try to add new items to the session or update existing values, ie:
Session["test"] = 4;
Session["faux"] = 8;
As I'm debugging, the initial "test" value never gets updated, and the "faux" value is never added. No error is thrown, and if I step into/over the update/add code, the session looks like it's being updated, but if I step into another function and try to query the session, only the original values exist in the session.
I followed these instructions: MSDN, and the tables are showing up on my server.
I'm at a loss. Why would I be able to create a session, but never update/add values in that session?

The issue was that in one controller I had [SessionState(SessionStateBehavior.Required)] (which was the controller that was working properly), and in the other controller (the one that was not working properly), I had [SessionState(SessionStateBehavior.ReadOnly)] set, which is why my session items were never being updated. This was not an issue when my session state was InProc.
I'm keeping this question open in-case anyone else makes the same bad mistake that I did.

Related

System.NullRefrenceException while trying to set Session in MVC

I am working on a MVC application where i have to store a unique id for the user who visits for a certain amount of time, so i am using Session in my MVC application but whenevr i try to set a value in my Session, i get a null exception. dont know the reason why, i tried
HttpContext.Session["demo"] = "name";
Session["demo1"] = "username";
I tried both the above method but i am not able to set the Session in MVC application.
I was calling this method on the constructor, thats the reason i was not able to get the Session, once i moved the code to the Action, everything was working fine.
thank you all

Session variable does not maintain value across different controllers

I am working with two controllers, they both save a value to Session but only one of the Controller manages to maintain it's value.
The line of code that saves the value is
Session["LoginDate"] = <dateTimeObject>;
and this is the same in both Controllers. The Second controller gets called from the First Controller and while in the second controller, if I set the value of Session then we're ok until I get back in the calling controller. If I call the First controller only, the value can get set and be sent back to the client.
I have tried modifying the second config file to include
<sessionState mode="InProc" timeout="30" />
and have made sure they are at the same version of .NET, MVC, etc...
Any ideas as to how to debug this? What else should I check?
UPDATE
Is there a way to pass the session state from different servers or would usign cookies be better since the cookie will be on the client browser? The new discovery is that the second controller does an
Redirect("serverOfController_1");
The controller gets initialised by the MVC core, so that it has the correct references to the context of the current request. When you create an instance of a controller yourself, that won't have any context at all, so it can't use anything from the controller interface.
For a method in that controller to work in that context, it can't rely on anything in the controller interface. If you want to set a session variable from that method, you have to get the current context and access the Session object from that:
System.Web.HttpContext.Current.Session["LoginDate"] = <dateTimeObject>;
You can also copy the controller context from the current controller after you have created the instance. That way the controller that you created will have the same context as the current controller. Example:
SecondController second = new SecondController();
second.ControllerContext = ControllerContect;
second.SomeMethod();

Alternative to appsettings in web.config (persistance needed)

I'm currently having some configuration variables in my Web.config, eg:
<appSettings>
<add key="RecipientEmailForNotifications" value="asdf#sdf.com" />
<add key="NotifyNewEntries" value="true" />
<!-- etc... -->
</appSettings>
I have a view where admin users can change this values online, eg.
/Admin/Configuration/
Recipient email for notifications:
[___________]
Notify new entries:
[x] Yes
[SAVE]
But there are two problems with this approach:
Each time I deploy the web.config, I'm overriding those values that were saved online
Each time the web application restarts (because web applications are naturally stopped when there is no activity), these values that were saved online are reset to the originals of the last deployment
So the question is:
What is the best way of achieving this goal of having configuration variables that have to be persisted?
I think that using a table isn't very natural, but I might be wrong (please explain why).
Also, using app settings is very convenient when reading the values:
ConfigurationManager.AppSettings["RecipientEmailForNotifications"]
As opposed of using the database,
db.SomeConfigurationTable.SingleOrDefault(.....)
I'd use a combination of database store and caching.
If you are on a single web server you could store the settings in proc cache. If you are in a web farm you could look at something like couchbase (free memcached) or azure.
It might make sense to warm your cache on applicaiton start. That is read the settings from your database and populate your cache.
Another popular approach is to have a Get call that check the cache first and populate cache if cache is empty, e.g.
public string Get(string key, Func<string> getItemCallback)
{
var item = Cache.Get(key) as string;
if (item == null)
{
item = db.SomeConfigurationTable.SingleOrDefault(key);
Cache.Store(key, item);
}
return item;
}
Not forgetting you will need to burst your cache when updating settings.

Maintaining a user object through a web session

I have followed a tutorial to implement LDAP (Active Directory) authentication to an ASP.NET/C# 4.0 Web Application. I have the authentication working, and am able to log in under a user of our domain. The next step however is not covered in this tutorial, where I need to keep a session-specific object with some variable data.
Now that I have LDAP authentication working, I'm making a class to wrap the session. However, I'm not sure how I can create this session in a way that it will stay active through all this user's requests. In Globals.asax, I have utilized Application_AuthenticateRequest as required in the tutorial. I'm assuming there's something I need to do here, but since I'm new to C# (more familiar with Delphi), I don't know where I need to actually declare/create this user class instance.
This class contains some things I'd like to keep accessible throughout this user's session, assuming of course the server will stay running throughout this time. For example, a dataset containing product data, which the user may request various parts of this same dataset in different requests. Therefore, it must stay accessible throughout the entire user's session, not just that single HTTP request.
I think you should have a look at Forms authentication for asp.net.
Web.config:
<authentication mode="Forms">
<forms name=".ASPXFORMSAUTH" loginUrl="/Login.aspx" timeout="120" />
</authentication>
<authorization>
<deny users="?" />
</authorization>
After you have managed to log in your visitor using ldap you can log in that visitor in your web-application with very little code:
PrincipalInfo.CurrentPrincipal = PrincipalInfo.CreatePrincipal(userName);
FormsAuthentication.SetAuthCookie(userName, true);
I would also give you an advice about using Session. Jeffery gives you a simple example of how to use the Session object. But don't go store multiple single values in Session; instead create a class like 'VisitorInformation' with all properties you will need. And then make a static manager that sets and gets that visitor information.
Visitor visitor = VisitorManager.CurrentVisitor;
string name = visitor.Name;
int age = visitor.Age;
private const visitorSessionKey = "visitorSessionkey";
public static Visitor CurrentVisitor
{
{
get { return (Visitor)Session[visitorSessionKey] ?? new Visitor(); }
}
}
This way you won't sprinkle your code with calls to session all over the place, with the increasing risk of spelling a key wrong or getting values out of sync.
You can read or write to Session almost anywhere in asp.net.
Examples:
using System.Web;
...
Session["UserAge"] = 28;
var userAge = (int)Session["UserAge"];
Session does have a timeout period, which may be configured in the web.config. As long as requests are being made to the browser, the session information should persist.
See MSDN for more info: http://msdn.microsoft.com/en-us/library/system.web.sessionstate.httpsessionstate.aspx
There is a built-in object called Session that allows you to add and retrieve things from the Session. They are looked up automatically via a session cookie that is maintained by ASP.NET.

Login failed for user ''. - ASP.NET MVC FormsAuthentication

My "Register" page used to work, until I started using FormsAuthentication and FormsAuthenticationTicket to login.
Now on Register, it fails when checking if an email already exists in the database, on this line
if (Global.DC.Users.Where(x=>x.Email == Email).Count() > 0)
return "The email address already exists in the database";
with this error message
System.Data.SqlClient.SqlException:
Login failed for user ''.
Does anyone know how to solve this? Thanks in advance.
Looks like the SQL login is invalid. I would check your connection string to see if that has changed, and if not, I would validate that the SQL Login and Database User is configured correctly.
Typically you may not realise this has happened if you are changing how your DataContext is being called, if you used to explicitly test it using a specific connection string, or create it with the default constructor (new ....DataContext()). Using the default constructor normally uses the design time connection string configured in the Settings.settings project item which stores the connection string name to reference in your web.config configuration file. Are you still calling it the same way?
On another note, I noticed you're calling your DataContext through your Global class. This is generally considered a bad design, and you should really consider using a unit-of-work` approach to data access, e.g., instantiate and release your context after you're finished with it:
using (var context = new DataContext()) {
// Do work here.
}
And another quick one, its more efficient to using Any instead of Count as using Count causes the entire enumerable to be enumerated to get the result, where as Any will fall out at the first valid instance.

Categories

Resources