views:

54

answers:

3

I have a web app which processes files and writes the data to a database. This process can take up to 2 minutes. Let's say this is done on ProcessFile.aspx. I wanted to ensure data integrity so I wrapped all the database processing in a TransactionScope.

The problem occurs when I am processing a file and then try to access another page which also accesses the database (just reads some data via a select statement). I'm pretty sure it doesn't have to do with any kind of database locking as when I go directly through SQL Server Management Studio, I have no trouble selecting on a table.

I am using LinqToSQL. I have a ScriptManager on the master page. All pages inherit from this master page. ProcessFile.aspx has an UpdatePanel but the other page does not.

What am I missing here? If more info is needed, comment and I'll update the question.

EDIT 1: I get this exception message

Type : System.Data.SqlClient.SqlException, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Message : Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.
Source : .Net SqlClient Data Provider

I open the second page in a separate browser window. It simply keeps loading UNTIL the first page has finished processing the file and then loads normally.

I'm not making a call from one page to another. Simply opening another page through another browser window via the address bar.

EDIT 2: This is the first time that I've come across where more than one answer solved my problem. Both Remus's and Rick's answers in conjunction solved it for me. I didn't know who to choose as the correct answer so I flipped a coin and Rick won. Sorry, Remus! I didn't want to give it to nobody. However, I needed to implement BOTH answers for it to work.

A: 

What problem exactly are you having - timeout? exception?
What do you mean access another page?
- In the same browser window?
- Another separate Window?
- Your making a call from one page to another?

Ralph Willgoss
+1  A: 

This is most likely database locking.

By default the TransactionScope uses serialisable transaction isolation level, which means that the first page will place range locks on everything it reads. The second page will try to do operations on these locked ranges and will conflict. Your SSMS select from table doesn't proove much, we know already that shared locks don't conflict.

Open the first page. Then open your second page and while is waiting, check the blocking list in the activity monitor. You'll find the requests from the second page blocked behind the locks held by the first page. The contention resource should indicate on exactly what operation the blocking occurs.

The simplest solution is to use the ReadCommited isolation level in the TransactionScope and to enable read commited snapshot in the database.

Remus Rusanu
Thanks for the answer. I have nested TransactionScopes. Would each of them also need to be set to have a ReadCommitted isolation level? I'm thinking yes?
Andrew
AFAIK no. The outermost scope must have an explicit isolation level, but inner scopes will inherit the TransactioOptions IsolationLevel of the outer scope. If the inner scope does specify an isolation level that is not the same as the outer scope, it will throw an exception, so is better imho to speicfy only at the outermost scope, if possible.
Remus Rusanu
This worked for me in conjunction with RickNZ's answer.
Andrew
+1  A: 

Are you using session state? If so, by default sessions use an exclusive lock, so you can only issue one request at a time.

You can work around this either by disabling session state for the long-running page, or by marking the page as only needing sessions in read-only mode.

RickNZ
Hi Rick. By sessions, do you mean session state?
Andrew
Yes, session state.
RickNZ
To anyone who has the same problem as I did. Please also look at Remus's answer as that was also needed to solve it.
Andrew