Reputation: 2073
I have ASP.net application that is basically a data entry screen for a physical inspection process. The users want to be able to have multiple browser windows open and enter data from multiple inspections concurrently. At first I was using cookie based sessions, and obviously this blew up.
I switched to using cookie-less sessions, which stores the session in the URL and in testing this seemed to resolve the problem. Each browser window/tab had a different session ID, and data entered in one did not clobber data entered in the other.
However my users are more efficient at breaking things than I expected and it seems that they're still managing to get the same session between browsers sometimes. I think that they're copying/pasting the address from one tab to the other in order to open the application, but I haven't been able to verify this yet (they're at another location so I can't easily ask them).
Other than telling them don't copy and paste, or convince them to only enter one at a time, how can I prevent this situation from occurring?
Upvotes: 15
Views: 55282
Reputation: 12521
Think of using ViewState instead of Session, since ViewState renders state information to the client (HTML page). I'm not sure if you'll ever be able to gain detailed control over the browser's session behaviour, because the session ID is maintained by the browser the way the manufacturer did it. So ViewState is more predicable, not only but also for future browser versions.
Upvotes: 5
Reputation: 4772
A solution to that problem can be implemented by the following:
public static class CommonHelper
{
public static bool SiteGuard
{
get
{
if(HttpContext.Current.Session["SiteGuard"] == null)
return true;
return (bool)HttpContext.Current.Session["SiteGuard"];
}
set
{
HttpContext.Current.Session["SiteGuard"] = value;
}
}
}
public partial class TestPage : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if(!Page.IsPostBack)
{
bool go = false;
for(int i = 0; i < 50; i++) // wait for the service to work (5 secs max)
{
if(CommonHelper.SiteGuard)
{
go = true;
break;
}
Thread.Sleep(100);
}
if(!go)
Response.Redirect("Login.aspx");
SiteGuard = false; // from now on, nobody can visit your site
}
// Now as long as Page.IsPostBack is true you are in a good shape
}
}
Add an asmx web service (or any other type of services you think is suitable) to your root project and add the following method to it:
[WebMethod(EnableSession = true)]
public void FreeSiteGuard()
{
HttpContext.Current.Session["SiteGuard"] = null;
}
In the master page, or on every page add the following javascript:
<script type="text/javascript">
window.onbeforeunload = function (e) {
e = e || window.event;
if (e) {
// Invoke web service
YourProject.YourWebServiceName.FreeSiteGuard();
}
};
</script>
Note that your site response time gets affected by the speed of the web service.
Upvotes: 2
Reputation: 13753
This is what I use in ASP.NET MVC to forbid authenticated users to open multiple tabs:
<script language="javascript" type="text/javascript">
@if(Request.IsAuthenticated)
{
<text>
if (window.name != 'singleWindow') {
window.location.href = "Content/ErrorPages/SingleTab.htm";
}
</text>
}
else
{
<text>
window.name = "singleWindow";
</text>
}
</script>
Basically, this sets the window name first time when the user visits the login page. After logging in, for each subsequent page load the window name is tested.
Two problems:
Upvotes: 2
Reputation: 9857
I am unsure why you wish to restrict a session to handle only one inspection process, and then force multiple sessions in order for users to work simultaneously on multiple inspections. That feels like a rather awkward style of isolation.
The web application (and pages) ought to be able to handle multiple inspection processes within a single user session.
Whatever data that is being held in Session variables should not be plainly exposed for singular handling. They ought to be stored in collections that readily identify which set of data belongs to which inspection process. Every page submission back to the web server ought to carry an identifier which inspection process it pertains to, so that the correct session set can be matched and pulled for use.
pseudo code concept
var inspectionID = this.inspectionLabel.Text;
var inspectionSets = (Hashtable)Session["inspections"];
var inspection = (Inspection)inspectionSets[inspectionID];
Upvotes: 3
Reputation: 31
this is a very good question that i have also thought long and hard about.
Store your main web page in an iframe. Have javascript to check if your web page is still in the parent iframe. If not, then they have opened multiple browser windows.
You need to make sure your entire app is iframe friendly.
Upvotes: 3
Reputation: 1928
Create a new sessionId when the request has no referer. That solves the copy-paste url problem. Store the sessionId in the url like you did.
Upvotes: 0
Reputation: 171559
Must the users be logged in with different accounts to access different physical inspections? It seems to me that as long as the PhysicalInspectionID
is part of the URL, then there should be no problem in editing multiple physical inspections at the same time.
E.g.,
http://inspections.mydomain.com/edit/23
Of course, if they copy the URL, they will get a duplicate of the other window, but this will teach them not to do that. Instead, they open another window and browse to the proper inspection (or add a new one) via the UI.
Upvotes: 2