How to implement a Windows Service to manage Session state? - asp.net

I'm working on an ASP.NET MVC web application that will be deployed across multiple load-balanced servers. With this setup, a user might have one request served by server A and the next request will be served by ServerB or ServerC.
We don't want to store Session Data in the database, as we're trying to minimise database hits where ever possible. As such, we need to have the HttpSession managed and stored on another server.
My understanding is that this is possible by using a Windows Service that will manage this for me, but I'm unfamiliar with how to implement this. Can somebody point me at some good documentation on how to do this? Or any pitfalls or other points to take into consideration? Thanks

You need to dedicate a machine that will host the Windows NT service and which must have .NET installed (well you could use one of the web servers as state server but IMHO this would be a very bad idea):
net start aspstate
And then instruct your application to use this server:
<system.web>
<sessionstate
mode="stateserver"
cookieless="false"
timeout="20"
server="127.0.0.1"
port="42424"
/>
</system.web>
where of course you would replace 127.0.0.1 with the IP address of the server hosting the NT service.
Note1: don't forget to decorate the objects you intend to store into session with the [Serializable] attribute.
Note2: this is a good solution in a load balanced environment but if you are looking for a real failover clustering you should use SQL server.
You may read more details about ASP.NET session state on MSDN.

As usual, Peter gives this issue good coverage...
http://www.eggheadcafe.com/articles/20021016.asp

Another alternative you may want to consider is Memcached Providers - it allows you to store session state in a memcached instance; optionally using SQL Server as a fallback. The best of both worlds, IMHO.

Related

Asp.net forms authentication IIS 7.5 with multiple servers

I have a Asp.Net web application running on Windows 2008 R2 (IIS 7.5). I have two servers WWW1 and WWW2 and the DNS records are set up for round robin DNS for "www". I increased the AppPool timeout and the Session State timeout settings so users don't get logged out after 20 minutes. However I've noticed users are getting logged out randomly. I think what is happening is the user goes to www.foo.com and logs in and then afterward some time the round robin navigates them to the opposite server in the cluster (WWW1 or WWW2) where the cookie was not created and therefore prompts them for a login.
How can I get this to work and still keep my high availability solution using round robin DNS?
The issue here is each server maintains its own session state in memory and doesn't know about sesssions created on the other server.
To get around this, instead of using the default InProc session state provider you'll need to use the StateServer or SQLServer session state providers.
To do this you'll need to make sure the ASP.NET state service is running on one of your servers and then you'll need to add the following configuration item to the system.web section of your application's web.config file, replacing 'SampleStateServer' with the name of the server you are running the ASP.NET state service on:
<sessionState mode="StateServer"
stateConnectionString="tcpip=SampleStateServer:42424"
cookieless="false"
timeout="20"/>
Microsoft's documentation on this is available at http://msdn.microsoft.com/en-us/library/ms178586.aspx
Because you are running this in a web farm you'll also need to make sure the web applications on both servers are using the same encryption keys.
For this you'll need to set a machineKey entry in the web.config whic involves adding an entry like the following to the system.web section of the web.config:
<machineKey validationKey="4D0590A0E4DE163BAD0EEEB6747467D770CD5FB2EA95BF02B27787A45CA579DECB01E2A1F16563DBAB44C1C0E54C7E53D65F2A7D0FDF378F4D3702B3F2C8B165" decryptionKey="928771D7B1B8C32608F56AC428EC5902985F6FB2E6E9A78733B6EAA493FA13F5" validation="SHA1" decryption="AES" />
There are several websites which will generate keys for you. I typically use http://aspnetresources.com/tools/machineKey
If you want to use the SQLState provider instead, http://msdn.microsoft.com/en-us/library/ms178586.aspx has all the configuration information under the 'Sql Server Mode' section of the page. The setup for that is slightly more involved as you have to configure a database in which you will store the state.

ASP.NET SQL Server Session State extremely slow

I'm having problems with an ASP.NET application that I need to web-farm, however just logging into my application takes at about 15 seconds
I did a little experiment where I created a non-web farmed version of my application and then used INPROC session state instead, and the login time is immediate. In this test instance, I'm running SQL Express on the same machine.
I know session state on SQL server is slower, but there is no way it should be THIS slower. Any suggestions on how to track down the issue?
This is my session state:
<sessionState mode="SQLServer" timeout="60" sqlConnectionString="Data Source=localhost;Integrated Security=SSPI;" sqlCommandTimeout="30" cookieless="false" useHostingIdentity="False" regenerateExpiredSessionId="True" />
I've tried both using a username password as well as integrated security.
Relational databases are Atomic (ACID), so give pretty poor performance when everyone is hitting the same table (ASPStateTempSessions).
We had the same problem as used the SessionState mode instead, we started the ASPNet State Service on the load balancer and used that. Much better throughput.
<sessionState mode="StateServer" stateConnectionString="tcpip=localhost:42424" cookieless="false" timeout="60" />
Your question spans a wide area -
Code: What things you are pushing into the session matters a lot. If you are storing large blobs etc, serialization/deserialization happens every time session data is stored and read from the database. Can you parse the data being stored and try to find out average size? I have seen business applications storing 1mb to 2mb data on sql server with thousands of users connected but then underlying hardware was capable enough to support the throughput.
Infrastructure: How much RAM do you have on your machine? Can you try running sql trace on your aspstate database to see how many connections are coming in and how long it takes to execute the query? The problem may not be on the database end, it might be your application trying to do something when storing session information.
SQL Server session storage is not this slow, on my machine with 8gig ram and asp.net application running through visual studio (IIS Express) it takes merely a second to connect and launch the application.
The best thing you can do (if your application permits) is to completely avoid a session storage backend. If the session data fits in the HTTP headers themselves (which usally does) you can have it encoded and move back and forth with the requests themselves as cookies.
Plus most implementations of session state provider are "blocking" so you cannot have concurrent requests for the same session, turning into a huge bottleneck.
This article points to a JWT based drop-in session state provider:
http://www.drupalonwindows.com/en/content/aspnet-session-state-scaling-and-performance-issues

Retrieve SSL session id in asp.net

Is there any way to retrieve the SSL session Id serverside in asp.net?
the short answer is no. This is an intentional limitation of IIS, so as to prevent people from taking a dependency on something that isn't dependable.
Out on the market, you will find various hardware load-balancers that will offer features like server persistence based on SSL Session ID, but they don't work very well because SSL renegotiation can happen at any time. In Internet Explorer 8, for example, a new SSL session is negotiated for every tab that is opened to a web site. You can expect similar behaviour from other multi-process browsers. So, I must stress that you should not use SSL Session ID for any kind of user identification purposes.
That said -- If you really need the SSL Session ID information for some specialized task, I recommend using Apache, mod_ssl and mod_proxy as a front-end to your IIS system. With a bit of fiddling, you could coerce mod_ssl into giving you the session ID, which you could then add to a proxied request to your IIS server as a query string parameter.... or you could store it in a database.
Tim,
Are you really "just" trying to retrieve the Session ID string or do you maybe lose all session information when switching to SSL? this would be a quite common problem, because the session on serverside is lost when using "InProc" session storage, and the session cookie on the client might be lost when not stored in a common domain.
Therefore, you should switch to state server or sql server session management in Web.config file, for example:
<sessionState mode="SQLServer"
cookieless="true"
regenerateExpiredSessionId="true"
timeout="30"
sqlConnectionString="Data Source=MySqlServer;Integrated Security=SSPI;"
stateNetworkTimeout="30" />
Beside that, I don't really know why you shouldn't be able to retrieve HttpContext.Current.Session.SessionID also in SSL mode as well.
Some MSDN Links:
MSDN: HttpSessionState.SessionID Property
MSDN: ASP.NET Session State Overview
Maybe this helps somehow.
Best regards

ASP.Net Persisting Data Across the Application

How Can I persist a User-Specific data for an ASP.Net application.
I tried Session Variable - Not good when the worker process recycles.
I need something that can be accessed GLOBALLY by any class of my application.
Advice most welcome.
I tried to utilize asp.net session State Server but I got some DLLs crashing because they are Unserializable.
Is there any other way to have a persistent variable across the application?
ASP.NET session state can be configured to persist to a database.
Here is a tutorial on how to set that up.
Store Data in a Database (such as SQL Server).
You should use Session. You can access session state globally in a class like this...
HttpContext.Current.Session
To avoid losing sessions by the worker process recycling, use StateServer mode.
You can change the Session State Server to not be in process which will make it far more stable and also seperate it from the worker process (You'll need to be able to start the Asp.NET State Service on the server if it's not already running)
<sessionState mode="StateServer" stateConnectionString="tcpip=127.0.0.1:42424" sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes" cookieless="false" timeout="20"/>
Also if you need to share it across applications in the same domain you should be able to give them the same machine key
Theres nothing you can really do about the process recycling. If you use the Cache smartly to retain information in a more global sense but you still have the same worker process limitation.
I try and design my app in a n-tier setup with business entity objects. The factory methods for my objects use the cache kind of like a lazy instantation pattern. If its in the cahce, pull it. If not, put it into the cache for next time.
i.e
MyAppsNameSpace.MyBusinessLayerNameSpace.MyObject.GetObject(objectID)
now when this returns my object, it may be from the cache or may not, if the object is under high usage then it will be probably be cached.
This can be used throughout your entire app and because the caching mechanism is maintained centrally you dont really have to worry about it.
You could use the Profile Provider with a SQL database as your backing store.
See this MSDN Article
If you lose data when the worker process recycles then you should stop using the InProc persistance mode for the Session. Use StateServer or SQL Server. Ultimately you could build your own session persistance module if neither satisfies you.

Can you share the session variables between two .net 2.0+ applications?

I was told this works, but...
I guess I'm just not getting this, it seems there's a hidden step I may be missing, can anyone correct this or point out my mistake? Thanks.
I have a blank solution:
- inside is two .net 2.0 web applications
1) webapp1
2) webapp2
I want them to share the same session data.
My page setups:
Application 1:
Session("value") = "this is the value"
Application 2:
If Not (Session("value") Is Nothing) Then
value = Session("value").ToString()
End If
My thought process:
1) go to services, turn on the asp.net state service
2) open the web configs in both projects: set the
< machineKey
validationKey="BFE2909A81903BB303D738555FEBC0C63EB39636F6FEFBF8005936CBF5FEB88CE327BDBD56AD70749F502FF9D5DECF575C13FA2D17CA8870ED21AD935635D4CC"
decryptionKey="2A86BF77049EBA3A2FA786325592D640D5ACD17AF8FFAC04" validation="SHA1" />
< sessionState mode="StateServer" stateConnectionString="tcpip=localhost:42424"
cookieless="false" timeout="20"/>
in both sites.
3) compile and test the site
4) become disappointed because it does not work. I never see the session from the second webapp.
You cannot share sessions between different ASP.NET applications without some custom code. What you did in web.config was to use an out of process sessions, which means that data will no longer reside into memory but into the memory of a dedicated machine. This is useful for server farms and it uses the ApplicationName to know which application the session belongs to. So basically your applications need to have the same name if you want them to share sessions. There are some dirty workarounds though.
Why do you want to share Sessions between applications? ASP.NET Session is not designed to do that.
Your proposed solution of using the same ASP.NET State Server does not work because your user will simply get 2 different session tokens, even if they use your 2 applications concurrently from the same machine, and same browser. You need to consider how Session works to understand why this is.
From MSDN:
ASP.NET session state enables you to store and retrieve values for a
user as the user navigates ASP.NET pages in a Web application. 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.
ASP.NET Session is a metaphor for a user's current interaction with one ASP.NET application. It exists in ASP.NET to give us a place to store temporary state data between the various page requests that a user makes while using your application.
If your applications are very closely related, e.g. the user uses both at the same time, or almost the same time, you could consider merging them into a single ASP.NET application. You could deploy them into different Virtual Directories to maintain some degree of logical separation, but use only one Application in IIS.
If your applications are not that closely related, perhaps they should be sharing the same database as a means to exchange data, or using an API e.g. based on Web Services to exchange information.
They will share session data if they are in the same app pool and the session mode is set to inproc. The way that stateserver and sqlstate work is they use the root of your web address as logical boundaries.
Eg if they are both hosted on the same address and port (or 'site' in iis) but in different sibfolders then they should share session I think.
Additionally both apps must run on the same domain so that user browser use one cookie to store session id.

Resources