Asp.net: How session works in a server farm environment - c#

I would like to know in how the Session locking mechanism work and how I can lock a variable and its respective child objects for multiple reads/exclusive write in a server farm environment.
Scenario
The web farm will use 3 Windows 2003 servers, each server as its own app domain for the Web application. The sesion object is saved on SQL Server 2005.
The object to use in my web app is at follows:
MySampleClass = class
{
public string Id;
public Dictionary<string, CustomClass1> Data;
public List<string> Commands;
public CustomClass2 MoreData;
}
where customClass 1 and 2 are business classes that are part of the application.
now in one of the web pages, code will look like:
Session["myObj"] = new MySampleClass();
in other pages:
MySampleClass = (MySampleClass)Session["myObj"];
//Is Session["myObj"] accessed in a multiple reader/exclusive writer mode? if so is it locking just the variable or the whole contents?
MySampleClass.Commands.Add("sample string");
MySampleClass.Commands.RemoveAt(0);
//More CRUD changes
//Are these changes available to other pages as soon as I finish the CRUD changes?
let me know if you need more details

Have a look here under Locking Session-Store Data. Basically, unless your page says it wants read-only session access, the session is locked on the DB and other callers for that session will poll at 1/2sec interval until it is unlocked.

There is also a detailed explanation on "Session State Providers" on msdn.
It covers the algorithm and rules used when using out-of-process session state providers in ASP.NET.

Related

Share Session Across Multiple Applications [duplicate]

I am trying to share sessions between two web applications, both hosted on the same server. One is a .net 2.0 web forms application the other is as .net 3.5 MVC2 application.
Both apps have their session set up like this:
<sessionState
mode="StateServer"
stateConnectionString="tcpip=127.0.0.1:42424"
/>
In the webform application I am posting the the session key to the MVC app:
protected void LinkButton1_Click(object sender, EventArgs e)
{
Session["myvariable"] = "dan";
string sessionKey = HttpContext.Current.Session.SessionID;
//Followed by some code that posts sessionKey to the other application
}
I then recieve it in the MVC application and try use the same session like this:
[HttpPost]
public void Recieve(string sessionKey )
{
var manager = new SessionIDManager();
bool redirected;
bool IsAdded;
manager.SaveSessionID(HttpContext.ApplicationInstance.Context, Id, out redirected, out IsAdded);
var myVar = Session["myvariable"];
}
The key is being posted but the session does not seem to get loaded in the MVC app, i.e. sessionKey is null. Can what I am trying to do be done?
I did it this way:
Basically the idea is both apps use native .net sessionState stored in sqlserver. By using the same machine key and making a small tweak to a stored procedure – both apps can share any session keys and/or forms authenication.
Both apps would do something like this in their web.config:
<sessionState mode="SQLServer" sqlConnectionString="Data Source=.\SQLEXPRESS;User Id=test;Password=test;Application Name=AppName" />
<machineKey
validationKey="SOMEKEY"
validation="SHA1" decryption="AES"
/>
Session state db would need to be set up on a database server, that both apps can see.
Docs for doing this:
http://msdn.microsoft.com/en-us/library/ms229862(VS.80).aspx
Command that would need to be run:
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin>aspnet_regsql.exe -E -ssadd --sstype p -S .\SQLEXPRESS
Stored procedure (TempGetAppID) tweak to:
#appId int OUTPUT
AS
-- start change
-- Use the application name specified in the connection for the appname if specified
-- This allows us to share session between sites just by making sure they have the
-- the same application name in the connection string.
DECLARE #connStrAppName nvarchar(50)
SET #connStrAppName = APP_NAME()
-- .NET SQLClient Data Provider is the default application name for .NET apps
IF (#connStrAppName <> '.NET SQLClient Data Provider')
SET #appName = #connStrAppName
-- end change
SET #appName = LOWER(#appName)
The problem is that session keys are scoped to the applications, so two applications having the same session key in fact have separate sessions.
You can do one of two things:
Put both applications as a virtual directory under a common IIS Application. I don't think this is a good idea, but it will work.
Roll your own session data solution for the data you want to share. Possibly using the backend database as the common storage, if you have one that is.
Based on Justin's comment, just to clarify option 2 is not refering to the SQL state managemet for out of process sessions. I mean for you to actually manually manage the shared data for the two sessions, possibly using a database.
You can use a common Machine key to generate same Session ID inside both applications for a given user. Additionally, you should also plan on storing sessions of both applications in a common store such as ASP.NET State Service or a distributed cache.
You can use NCache distributed cache which takes provides session sharing feature between different applications. You specify same Application ID tag for both apps inside session state settings which allows you to share session object provided you have same Session ID generated for both applications.

Emulating concurrency or multi threading in WCF C# application

I am developing an Service-Oriented based application for Hotel Reservation System using WCF architecture. It has following 3 three components:
1. WCF Service that has Service and Data contracts for invoking moudules of room reservation.
2. WCF Host that keeps log of service access by client
3. WCF client that has UI for Hotel Reservation.
I am looking for guidelines to implement concurrency in my application having following features:
1. Only one request shall be entertained at the time.
2. If more than one requests are received, then these should be synchronized using locks/mutex/semaphores.
Coding guidelines shall be helpful.
I think this is the allocation issue of the external resources, such as the database access, the I/O for on the single file. WCF supports transaction and transmitting it on the client-side. We are capable of locking the access to the database by using transaction when another client attempt to access it.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/transactions-overview
Moreover, we can also use the shared lock which locks the service instance, occupying all the resource lest the other instance access the service, please refer to the below code.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall,
ConcurrencyMode = ConcurrencyMode.Multiple)]
class MyService : IMyContract
{
public void MyMethod()
{
lock(typeof(MyService))
{
...
MyResource.DoWork();
...
}
}
}
static class MyResource
{
public static void DoWork()
{
lock(typeof(MyService))
{
...
}
}
}
Please refer to the below link, Chaper8(concurrency management), resources and services, deadlock avoidance.
https://ashishmit99.files.wordpress.com/2013/01/oreilly-programming-wcf-services-3rd-edition-aug-2010.pdf
Here is an official document relates to Concurrency mode, aiming to solve access conflict from the multiple users.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/sessions-instancing-and-concurrency

how to handle static variables when application (desktop c#) is configured on LAN

I built an c# desktop application for attendance
application is working fine when i run it on single machine and all is good..
but now issue is ... my boss want this application should work on LAN and every client can access application from server
but i used static variables which store some values at run time and then i utilized these values in next forms.
here is example..
on login form username is stored in static variable as
public static string username;
username = txtUser.Text.Trim().ToString();
and in next form which is Home Page this user name is used as
lblName.Text = Login.username;
here lblName is name of label and Login name of Login form
when i configure this application on LAN then may be at same time more than one user will be logged in and want to access application then each user should see his/her own username....
e-g abc is user 1 and xyz is user 2
if both are logged in at same time then i want abc to see
lblName.Text = "abc"
and xyz to see
lblName.Text = "xyz"
so what should i do to handle this job?
i need not to mix up any information between users...
i used c# windows app.
thanks in advance.
I assume you use static variables on server-side, right?
So, your issue happens because you use static variables.
Static variables are consistent in your class during all period of application is running. And that fields are shared between ALL processes which can use that class. Static variables was designed for this.
As a possible quick solution you can generate something like unique session Id. During client logs in to your system - you need just generate that id on client's side, send it with login information to server. In case of successful authentication server will store id in cache a key. And value of the cache can be object with user's name and other needs.
Every request to your server should be followed with that id. So your server will always know which user it is.
If you need more detailed answer please provide more information about app network structure and it's modules.

Managing user operations synchronization on Azure Cloud Service

I have .net4.5 WebRole project running on local IIS (dev purposes) and on Azure as Cloud service.
This project is handling request from users. Requests for one user can came from many clients types, for example from WWW (another project hosted on IIS and Azure), android app and windows application. There is one layer which translates each request type to some general request with User as parameter. User is an entity.
To communicate with database (MS SQL EXPRESS or AzureSQL) I'm using EntityFramework.
The problem is with synchronization. I'd like to have synchronized request handling per user. There could be thousands of users, some not active, some hardly ever active and some active all the time. I want to avoid slowdown caused by some mutexes.
This code would probably work, but will be extremely slow:
private Object allUsersMutex = new Object();
private Dictionary<long, Object> perUserMutex = new Dictionary<long, Object>();
private Object getUserMutex (User user) {
synchronized (allUsersMutex) {
if (!perUserMutex.containsKey(user.ID)) {
perUserMutex[user.ID] = new Object();
}
return perUserMutex[user.ID];
}
}
and then, on all methods I could get mutex by this method and synchronize on it.
Is there any mechanism helping with something like this?

Will this be global for the whole site?

I need to load an xml file into memory and have it available for globally for the whole site. Does this code accomplish this?
If so, how is updating this "cached" version accomplished in the future?
XPathDocument ConvProductDoc;
ConvProductDoc = Cache["doc"] as XPathDocument;
if (ConvProductDoc == null) {
ConvProductDoc = new XPathDocument(HttpContext.Current.Request.MapPath(#"\data\foo\bar\my.xml"));
Cache.Insert("doc", ConvProductDoc);
}
Yes, the ASP.NET Cache object is site wide. There are a lot of options for managing the Cache and setting expiration rules, etc.
To assign/update the value in Cache, you simply set it like you would any Dictionary or HashTable value:
Cache["doc"] = newValue;
You can read a lot more about the Cache object in the MSDN Docs here: http://msdn.microsoft.com/en-us/library/aa478965.aspx#aspnet-cachingtechniquesbestpract_topic4
If you website is only on one server then yes.
If your website is distributed over more than one server then no.
The cache key and data will only be available on the server in which it has been stored.
If you server is in Amazon EC2 for example, you could use ElastiCache which would ensure the cache is available over a distributed server environment.

Categories