I'm currently designing a new website built on MVC and I wonder what is the right way to manage state.
The state should contain the userId and some structs of the user info, and should be kept during the whole session of the user while he's logged in (across http requests)
The important criteria:
1) Support scalability
2) Performance
The easy way is to use the Session object, but it doesn't support scalability. If different requests during the session go through different IIS servers, the session won't be kept. Although I've heard of load balancing tools which route all requests of a single session through the same machine, I'm not sure that it's a good practice to rely on it (isn't it?)
Another option that I've read about, is keeping the state data in special state servers which are running a RAM DB (like Cassandra for Linux or Redis for Windows). But it seems to me an overkill at this stage of the development.
Do you have any other suggestions?
I would like to start with something simple at the moment, but keep the design ready for a more advanced solution at the future.
Any best practice or code/design suggestions will be appreciated.
Thanks,
Edi.
(1) Use Sql Server to Store Session State
(2) Use Memcached as a Session State Provider
(3) Cook up your own solution using Caching on an external caching provider: look into using something like the ServiceStack Caching Framework. Using this, you can use Redis, Memcached, Azure or AWS to handle caching.
Next, create a KeyFactory to handle generation of keys for specific items. The item keys would include the UserId (which you would always have from FormsAuthentication UserId (assuming that you are using FormsAuthentication). Then store any Session data for the user in the cache. Using this approach you are using Caching in place of Session, and the cache can be shared across multiple servers.
Note: you can have different approaches regarding clearing out the user's data whenever they begin a new session. Potential approaches include:
Include the user's session start dateTime in the cacheKey, and auto-expire entries when they are no longer fresh
Clear out all potential entries for a user when they begin a new session
If you are using .NET 4.5 and dependent on the type and amount of information you are keeping on users you may want to look at using claims to store information about the user. In .NET 4.5 all Principals inherit from ClaimsPrincipal. ClaimsPrincipal already uses claims to store the user name, roles and other information. You can create your own service to transform claims, which will allow you to add additional information to the Principal user.
Related
Now I'm reading a book and in the book it says:
"Both Session State and Application state are used for storing a small amount of insecure global information that does not change frequently"
Based on that I have five questions:
In MVC4 we can access session by HttpContext.Session, what's the difference
between this and HttpContext.Current.Session?
What's application status used for?
What's the practical difference between Session and Application state?
For which user info we cannot store in session but only store in server database?
Many many browser side cookies have been disabled, does that mean cookie are no longer in use when developing web application?
I hope this is not only helpful to me but also will help others who see this
Any suggestion are welcomed!
There is no difference. Use HttpContext.Current.Session when you are not on a view.
For storing application-wide information that applies to all users. There is only one at a time and the values are the same for all users.
Sessions are at a user level. Application is system-wide. If you need to keep information specific to a user, use session. If the value will be the same for all users, use Application.
Not sure what you mean
They both point to the same object.
ApplicationState if for sharing data between different Session objects which are tied to a concrete user session
I stated the main difference under the previous point. To elaborate: objects stored in Session are only accesible to requests that are run under that session (they have session cookie or identification string in url). Objects stored in Application, on the other hand, are available everywhere (for instance in global.asax) and are not dependent on current user.
It depends on your paranoia level. I would not store credit card information or social security number or passwords in an unencrypted format in Session. On the other hand I would not store them unencrypted on the database as well. SessionState can, by the way, be configured to reside in database and thus be shared between different machines.
ASP.NET functions better with cookies. There are ways of making it work without cookies, but it will involve a lot of work.
I have a application that has been programmed with MVC/EF Code First. It does a lot of server side processing and is pretty resource intensive.
I know how to set up load balancing, but, I want to know if scaling an EF application is as simple as provisioning a new server, deploying the application and pointing to the DB cluster - or are there any issues I will face with regards to multiple EF applications hitting the same database server?
I can't seem to find any advice/guides for this and I am worrying I made the wrong choice by choosing EF over something simpler/more straight forward!
... issues ... regards to multiple EF applications hitting the same database server?
Rewind a bit to the fact that your application is an ASP .NET MVC based application. Having multiple instances of it is probably going to raise the spectre of state management.
MSDN has a pretty good introduction to why this is an issue:
HTTP is a stateless protocol. This means that a Web server treats each HTTP request for a page as an independent request. The server retains no knowledge of variable values that were used during previous requests. ASP.NET session state identifies requests from the same browser during a limited time window as a session, and provides a way to persist variable values for the duration of that session. By default, ASP.NET session state is enabled for all ASP.NET applications.
Alternatives to session state include the following:
Application state, which stores variables that can be accessed by all users of an ASP.NET application.
This point is an extremely common way of storing state, but breaks down when there's multiple instances of an application involved (the state is "visible" to only one of the instances).
Typically this is worked around by using either the StateServer or SQLServer value of SessionStateMode. The same article provides a pretty good summary of each option (emphasis mine).
StateServer mode, which stores session state in a separate process called the ASP.NET state service. This ensures that session state is preserved if the Web application is restarted and also makes session state available to multiple Web servers in a Web farm.
SQLServer mode stores session state in a SQL Server database. This ensures that session state is preserved if the Web application is restarted and also makes session state available to multiple Web servers in a Web farm.
If your application is stateless, this is a moot point.
I am worrying I made the wrong choice by choosing EF
As far as issues with multiple instances of your application accessing a database go, you're going to have issues with any sort of data access technology.
Here's the basic scenario: let's say your application sends welcome emails to users on a schedule.
Given the table Users:
UserId | Email | WelcomeLetterSent
-------+-----------------+------------------
1 | user#domain.com | 0
And some psuedo-code:
foreach (var user in _context.Users.Where(u => !u.WelcomeLetterSent))
{
SendEmailForUser(user);
user.WelcomeLetterSent = true;
}
_context.SaveChanges();
There's a race condition where both instance one and instance two of your application might simultaneously evaluate _context.Users.Where(...) before either of them has the chance to set WelcomeLetterSent = true and call SaveChanges. In this case, two welcome emails might get sent to each user instead of one.
Concurrency can be an insidious thing. There's a primer on managing concurrency with the Entity Framework over here, but this is only the tip of the iceberg.
The answer to your question? It depends on what your application does :)
On top of that, I ideally want to build some "extra" support applications that hook in to the same DB... and, I am just not sure how EF will handle multiple apps to the same DB....
If your application can tolerate multiple instances of itself accessing one database, then it's usually not a stretch to make these "support applications" play nicely. It's not much different whether the concurrency is from multiple instances of one application or multiple applications with one instance each.
I would like to be able to share some data between an asp.net mvc application and a python/django application . The type of data I would like to share are authentification or session data.
This is of course possible as long as you access some shared resources between both frameworks. There are likely several ways of doing it but one of the most obvious would be using some shared backing store ie. database or maybe even memcached which would be faster. I'm not a Django user but as far as I know memcached is supported in it...
There is of course a more complex scenario related to this and that is data compatibility. You will likely have to use some interchangable format that both frameworks understand ie. XML, JSON, BSON or similar. So even when using memcached you will have to do this translation.
How I would share session...
Make the Session Cookie sub-domain agnostic
<httpCookies domain=".mydomain.tld" />
Have my two sub-domains that I want to share session between
www.mydomain.tld [ASP.net MVC app]
extra.mydomain.tld [Python app]
Create a simple web service or generic handler in ASP.net that returns the user's session serialized in JSON or XML.
If you use generic handler remember to use the IReadOnlySessionState or IRequiresSessionState interfaces on the class.
Now from extra.mydomain.tld you can call your www.mydomain.tld/[Get/Set]SessionValue handler or service. It will pick up on your ".mydomain.tld" cookie and allow sharing modifying values.
I would recommend the following approach using a shared database (could be a shared cache or any other datastore):
When a user accesses one of your applications at your domain, you create a cookie with the key "_shared_session" and with the value of a random string generated by your application;
Save the value of this cookie into the database and relate it to a JSON object holding the data you want to share between applications;
When the user accesses the other application, you verify if the cookie with the key "_shared_session" exists and read its value;
With the value of the cookie, you can retrieve the shared JSON object.
Quick answer: there should be a filter that look for a shared cookie before creating a new session
There is an option for storing Session state in MS SQL Server database which is available out of the box. Use the steps from the next kb http://support.microsoft.com/kb/317604
It's more about configuration, not implementation.
You can write your own custom storage provider but is there any reason for that?
I'm not familiar with python, but there are at least ODBC drivers for it
http://wiki.python.org/moin/SQL%20Server
Greetings,
Windows Azure only supports SQL Azure Session State for multiple instances.
I'm thinking what whether storing the objects in session will boost any performance for given scenario below:
Scenario:
I've got MVC Application where it's header and footer are populated from DB. I've created ApplicationController which inherits from controller. This applicationcontroller in turn will be inherited by actual controllers such as Home/Account etc.
I'm thinking of loading all these footer/header value in to session and use the session object for any subsequent requests.
Does anyone know whether this will boost any performance? Only reason I'm asking is that SQL Azure Session would do the same thing i.e. query SQL Azure Session storage for each request?
Thanks.
I would say that right now the amount of performance improvement you get from one option over the other is pretty negligible. The only way to know for sure would be to create some test scenarios.
Having said that, App Fabric Caching is coming out of CTP in less than a month and includes a session provider. If you were willing to use it you'd have two options:
Use the App Fabric Caching session provider and the session technique you've described above and it should be faster than either of the SQL options
Use the cache directly to provide the header and footer information (you'll still need to keep the data in SQL, but you can populate the cache on demand when headers and footers are requested)
I notice in the azure examples they are using:
<sessionState mode="Custom" customProvider="TableStorageSessionStateProvider">
Can someone explain what this is used for with MVC3? I'm very confused about session state. Do I really need to use it if my application does not have anything like a shopping cart? Is it needed if I just want to do simple authentication? I removed the code from my web.config and my authentication still seems to work.
If you're publishing your application to Azure and you're using Session in any way (this includes MVC's TempData) then you will probably need to use some kind of central storage for session, rather than using the default "InProc" provider which just stores the user's session in the application's own memory. With azure, you can use, among others, SQL Azure or the AppFabric Cache (still in CTP).
Here is a good lab for AppFabric:
http://msdn.microsoft.com/en-us/gg457897
And here's one for SQL Azure (not supported): http://blogs.msdn.com/b/sqlazure/archive/2010/08/04/10046103.aspx
This is because you could have mutiple instances running or you instance could be moved at any given moment.
It sounds like your application doesn't currently use Session State so you won't need to worry about it. (although, remember that the TempData dictionary uses Session under the hood)