So I have a WCF service, inside which there's a Process() method. This method reads a byte array (a file) from one table, and basically puts that data from that file into multiple tables. It just iterates through each row. It was working fine since a month in the Production environment. Now all of a sudden, it throws this error intermittently:
System.InvalidOperationException: The transaction associated with the current connection has completed but has not been disposed. The transaction must be disposed before the connection can be used to execute SQL statements.
Something which might help: About 2 weeks ago, we changed out Production web & DB servers. This error has been throwing up only after we moved. I have never encountered this problem when we were on the Old Servers. But the thing is, this error didn't occur in the first 9-10 days. Now it's happening suddenly and intermittently. I've uploaded large files (1k-2.5k rows) and they have worked fine, and this error throws up for much smaller files which have 200 rows! And the Service processes the same file perfectly sometimes.
Code snippet: (it's much larger, but similar operations are repeated)
using (var scope = new TransactionScope())
{
// loop through each row/invoice
foreach (var row in Rows)
{
Invoice invoice = (Invoice)CreateObjectWithConstantData(typeof(Invoice), doc, applicationName);
invoice = (Invoice)FillObjectWithUserData(invoice, row, -1, -1, string.Empty);
invoice.InvoiceNumber = InvoiceDBImpl.SaveInvoice(invoice, processFileRequest.RunId);
if (invoice.InvoiceNumber == Guid.Empty)
{
throw new DataAccessException(string.Format(Messages.ErrorSavingInvoice, invoice.ReceiptId, invoice.ProductID));
}
}
}
One of the Stack Traces:
at System.Data.SqlClient.TdsParser.TdsExecuteRPC(_SqlRPC[] rpcArray, Int32 timeout, Boolean inSchema, SqlNotificationRequest notificationRequest, TdsParserStateObject stateObj, Boolean isCommandProc)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at System.Data.Linq.SqlClient.SqlProvider.Execute(Expression query, QueryInfo queryInfo, IObjectReaderFactory factory, Object[] parentArgs, Object[] userArgs, ICompiledSubQuery[] subQueries, Object lastResult)
at System.Data.Linq.SqlClient.SqlProvider.ExecuteAll(Expression query, QueryInfo[] queryInfos, IObjectReaderFactory factory, Object[] userArguments, ICompiledSubQuery[] subQueries)
at System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query)
at System.Data.Linq.DataContext.ExecuteMethodCall(Object instance, MethodInfo methodInfo, Object[] parameters)
at Tavisca.TramsFileService.DataAccess.TramsDBDataContext.SaveTramsPayment(Nullable`1 paymentDate, String paymentType, Nullable`1 totalAmount, String bankAccount, String paymentMethod, String branch, String remarks, String creditCardLast4, String payeeName, String profileNumber, Nullable`1& paymentId)
at Tavisca.TramsFileService.DataAccess.PaymentDBImpl.<>c__DisplayClass1.<SavePayment>b__0(TramsDBDataContext dc)
at Tavisca.TramsFileService.DataAccess.SystemDataContext.PerformOperation(Action`1 action)
at Tavisca.TramsFileService.DataAccess.PaymentDBImpl.SavePayment(Payment payment)
at Tavisca.TramsFileService.Core.TramsFileController.ProcessFile(ProcessFileRQ processFileRequest)
at Tavisca.TramsFileService.ServiceImplementation.TramsFileServiceImpl.ProcessFile(ProcessFileRQ processFileRequest)
I've been through some links:
They all suggest increasing the TimeOut on the machine.config, but I'm not sure why it works sometimes and does not work the other times. Shouldn't this be consistent?
First of all I will suggest adding scope.Complete();
at end of TransactionScope
like :
using (var scope = new TransactionScope())
{
//Your stuff goes here
scope.Complete();
}
Any transaction must be committed at last line using .Complete()
function.
Secondly if increasing the TimeOut
on the machine.config
works, there is no harm in doing it, since long file obviously needs more time.
Thirdly make sure any other component called inside TransactionScope
are working for all positive & negative scenarios. By stacktrace, it seems in particular use case some is breaking inside function Tavisca.TramsFileService.ServiceImplementation.TramsFileServiceImpl.ProcessFile(ProcessFileRQ processFileRequest)
Also make sure if some stored procedure is used by any underlying call inside TransactionScope
then any failed transaction inside stored procedure can also result TransactionScope
.
One more thing, exception thrown could be legitimate one also since you are throwing exception manually when invoice.InvoiceNumber == Guid.Empty
but its not mentioned if it is handled/ catched or just passed to upper layers.
But first of all try adding scope.Complete();
, this alone could be root cause.