3

I’m working on an administration tool for a project that does a small amount of reading and writing to different files and some database queries and updates. Now I believe it’s improbable that we would ever have an issue with this since we’re not that many people using this project. But if I can, I want to minimize or eliminate the risk of it ever happening while not disturbing the normal users. I'm using Windows Authentication and Roles.

One of my ideas is to create a lock and only allowing 1 user to administer at the time. By using the Session.SessionID and saving it in the Application state as an exclusive lock. E g if a user would want to administer he would first go to a landingpage and there where would be this check (oh, this isn't atomic I take it?):

if (Application["lockedBy"] == null)
{
    Application["lockedBy"] = Session.SessionID;
    Application["lockedName"] = User.Identity.Name;
    Response.Redirect("Admin.aspx");
}

And the admin page there would be a button to release the lock and redirect to another page. Or if the user forgets using the Session_End() in the global.asax file and having an autorefresh. But how would this stop someone from pressing the browsers backbutton and bypassing this?

Or should I try to make sure the configuration files haven’t been changed before writing to them? But how would I save the state for this page. Should I like save the files modification time in Session state and if they diff just abort the save action?

So the question is: how should I protect my application from concurrency issues while not disturbing the normal users?

Teletha
  • 603
  • 1
  • 11
  • 21

2 Answers2

3

Call Application.Lock before accessing your files and then you can check for modifications and then release the lock when you have finished

Bob Vale
  • 18,094
  • 1
  • 42
  • 49
  • But the Application.Lock() only locks the Application state variables. How would this protect the files? – Teletha Aug 10 '11 at 08:22
  • Because you can use the feature in the same way you wanted to use application["locked_by"] with the bonus that the framework will handle the release for you at the end of the request and that the lock action would be atomic. You can then put your own detect logic to either return sorry someone else as made a change or intelligently handle it instead. – Bob Vale Aug 10 '11 at 08:56
  • After some testing it seems like you are absolutely right about Lock(). Awsome – Teletha Aug 11 '11 at 06:25
1

Teletha,

I'd try ReaderWriterLockSlim (if you have 3.5 or 4.0) or ReaderWriterLock (2.0) instead of lock. It has two queues one for reads and one for writes. Even though there shouldn't be that many admin users it works better in a multi threaded environment and would reduce (not remove) the potentials deadlocks. On the ReaderWriterLockSlim look at the TryEnterWriteLock method. It has an optional timeout option, but that may not matter for your scenario.

MSDN Magazine Feb 2005: Using the ReaderWriterLock Class

MSDN - ReaderWriterLockSlim Class

Stack Overflow - ReaderWriterLock vs Lock

Community
  • 1
  • 1
Charles Byrne
  • 834
  • 2
  • 11
  • 20
  • That’s an awesome suggestion. It doesn’t seem to solve everything but it will really help (like if user X reads the data, waits for 3 min and then writes, there might been a write by user Y while X waiting). – Teletha Aug 15 '11 at 07:58
  • It won't solve all the problems of concurrent reads & writes. Especially when you have more than 1 resource that needs to be locked at a time and/or there is a high concurrency in reads. Application.Lock doesn't scale as well in a multi-threaded environment and can affect the performance of the app and validity. If there is going to be a 3 min timespan then you might want to do 2 reads. First, read resource & timestamp then release lock. When user is ready to write do another read to resource & timestamp again. If timestamp matches then upgrade lock & update data & timestamp, otherwise error. – Charles Byrne Aug 15 '11 at 13:10