I built a MSMQ WCF service that is transactional. I used the following attribute on my operation:
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
I am using Nhibernate in service . Using Nhibernate I give a commit on my session. If I disable the Nhibernate commit the message is correctly processed and removed from the queues. With this commit, Nhibernate transaction goes correctly but my message goes into the retry queue.
Here is the exception that I get into Nhibernate service trace.
Description Handling an exception. Exception details: System.Transactions.TransactionAbortedException: The transaction has aborted. ---> System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'Transaction'.
at System.Transactions.Transaction.DependentClone(DependentCloneOption cloneOption)
at System.Transactions.TransactionScope.SetCurrent(Transaction newCurrent)
at System.Transactions.TransactionScope.PushScope()
at System.Transactions.TransactionScope.Initialize(Transaction transactionToUse, TimeSpan scopeTimeout, Boolean interopModeSpecified)
at System.Transactions.TransactionScope..ctor(Transaction transactionToUse, TransactionScopeAsyncFlowOption asyncFlowOption)
at System.Transactions.TransactionScope..ctor(Transaction transactionToUse)
at NHibernate.Transaction.AdoNetWithDistributedTransactionFactory.DistributedTransactionContext.System.Transactions.IEnlistmentNotification.Prepare(PreparingEnlistment preparingEnlistment)
--- End of inner exception stack trace ---
at System.Transactions.TransactionStatePromotedAborted.PromotedTransactionOutcome(InternalTransaction tx)
at System.Transactions.TransactionStatePromotedEnded.EndCommit(InternalTransaction tx)
at System.Transactions.CommittableTransaction.Commit()
at System.ServiceModel.Dispatcher.TransactionInstanceContextFacet.Complete(Transaction transaction, Exception error)
It seems that the nhibernate commit destroys the transaction on WCF. I cannot find the way to fix this.
Any help may be appreciated
I'm not too familiar with these systems, but the simplest answer is usually the right one, so I'll give it a shot - at a guess, I would say that whatever service you're calling the items to is stopping the process that removes the items before it has a chance to remove them, so I would add some sort of function call into the service you're calling the items to so it is forced to remove the item from the list before it can finish the transaction.
Of course, I'm not familiar with this topic, so don't take my word for it - that's just generally what I would do for a similar problem within the bounds of my programming knowledge.
Related
I have got a service that should use distributed transactions.
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public bool ServiceMethod(int parameterPlaceHolder)
{
return SomeOperationResult();
}
For reasons out of my responsibility, this service should never throw faults. On success it returns one value, on failure another (abstracted to a bool here for demo purposes).
The transaction flowing works.
However, the attribute implies that any result that is not an uncaught exception will complete the transaction. That's not the behavior I want. I want to control the outcome of the transaction myself. On returning false, I want to have the transaction fail.
I have tried various methods:
The obvious one: setting TransactionAutoComplete to false. This means that I have to use a session based service. I don't want to. I don't need to. I'm perfectly fine with a single transaction scope per call. But it's not allowed. ("TransactionAutoComplete set to false requires the use of InstanceContextMode.PerSession.")
The DIY one: setting TransactionScopeRequired to false and using my own. This means the flowed transactions no longer work and I create a new local transaction every time.
The desperate one: Trying to get hold of the transaction that WCF creates and rolling it back on my own... this leads to my service throwing exceptions because it tries to AutoComplete a transaction that is long gone.
I'm out of ideas. Does anyone know how to create my own transaction scope, using a flowed distributed transaction, not using the Microsoft AutoComplete-On-Normal-Return pattern? I would like to not complete the transaction without throwing an exception.
Transaction scopes can nest. The entire transaction aborts if you don't completed any scope. So:
using (new TransactionScope()); //Doom transaction
Better comment this line.
You can also try to call stuff on Transaction.Current but I have no experience with that.
I'm using SQLite 1.0.89 with EF 5 .NET Framework 4.5 on VS2013 in a WPF application in C#.
The DB size is not big and the table that the program use contain max 1000 row.
using the program I found this error often:
An error occurred while reading from the store provider's data reader.
See the inner exception for details.
the inner exception is :
{"library routine called out of sequence\r\nnot an error"}
Other time the inner exception is:
Connection was closed, statement was terminated
Another time i found:
unknown error\r\nno connection handle available
I found this article searching:
Parallel.Foreach loop creating multiple db connections throws connection errors?
SQL Server CE database size issue
but no one solve my problem.
The query that the program do IS NOT inside a loop, but are single query performed when button is pressed on the UI but i noticed that the error happens more often (bun not only) when I press the query button a lot of time faster.
Other thing. The error happens more often (but again not only) when the DB Context is access via a properties istead of a method example:
public List<Product> ProductList
{
get {
return DBContext.Products.ToList();
}
}
The problem was caused by multiple thread that query the db using the same DBContext.
Using a different DBContext for each thread solve the problem.
In my case I was using Castle Windsor to inject the DBContext into the class that perform the query.
Configuring the lifestyle of the DBContext to one per thread the problem has gone.
I had this error occur in EF6.1 and took me a while to figure out what was going on. Simplified the query, and it worked, so I figured something must be going on in the query. Found out I was querying a string and passing a compare on an int. once I changed the int.toString all worked.
Dim OpenOrder = (From p In context.CP_Carthead Where p.SessionID =
MySessionInfo.Current.LeadID.ToString And p.CustomerID = LeadID
And p.Deleted = False And p.PortalID =
TenantID).OrderBy(Function(p) p.OrderID).FirstOrDefault
OrderID = OpenOrder.OrderID
LeadID (my Session) is an int. without the .ToString I get the error in the above post
I experienced this error today on a production application.
This was caused by a user, for some reasons, installing the program and its dependencies on a OneDrive-enabled folder. This triggered a whole lot of bugs including this one. Hope it saves someone's day.
An unhandled exception occured.An error occurred while reading from the store provider's data reader. See the inner exception for details. at System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.HandleReaderException(Exception e)
at System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.StoreRead()
at System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.SimpleEnumerator.MoveNext()
at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
Im sure I understand those properties all wrong.
ReleaseServiceInstanceOnTransactionComplete -
from what I understood- dispose your service instance that you initilize in your client after your transaction there complete\abord.
2.TransactionAutoComplete-
from what I understood- dispose your service instance that you initilize in your client after the opertion ended.
My english isnt that good so after reading each article, I still have peaces that i dont understand.
Thank you for your time.
EDIT 1:
Can you expline to me in simple english what is the purpose of InstanceContext?
I have read this article : http://www.danrigsby.com/blog/index.php/2008/05/23/understanding-instancecontext-in-wcf/
and still didnt get it.
ReleaseServiceInstanceOnTransactionComplete really disposes your service instance when the transaction is completed or aborted. It is by default set to true. If you for example create service with PerSession instancing you may want to turn it to false to ensure your session lifetime instead of transaction lifetime.
TransactionAutoComplete has nothing to do with disposing. It just controls transaction used to execute operation. If TransactionScopeRequired is set to true, your operation will be automatically wrapped by TransactionScope. TransactionAutoComplete set to true will than automatically commit transaction if the operation executes without error or rollback transaction if operation throws exception. If you set TransactionAutoComplete to false you will have to commit transaction manually by calling:
OperationContext.Current.SetTransactionComplete();
I have a workflow inside a Windows Service that is a loop that performs work periodically. The work is done inside a TryCatch activity. The Try property is a TransactionScope activity that wraps some custom activities that read and update a database. When the transaction fails, I would expect any exception that caused this to be caught by the TryCatch. However, my workflow aborts. The workflow I have is the following:
var wf = new While(true)
{
Body = new Sequence
{
Activities =
{
new TryCatch
{
Try = new TransactionScope
{
IsolationLevel = IsolationLevel.ReadCommitted,
Body = new Sequence
{
Activities = { ..custom database activities.. }
},
AbortInstanceOnTransactionFailure = false
},
Catches =
{
new Catch<Exception>
{
Action = new ActivityAction<Exception>
{
Argument = exception,
Handler = ..log error..
}
}
}
},
new Delay { Duration = new InArgument<TimeSpan>(duration) }
}
},
}
In my case, it's possible that the database is sometimes unavailable so obviously the transaction won't commit. What happens in this case is that the workflow aborts with the following exception:
System.OperationCanceledException: An error processing the current work item has caused the workflow to abort.
The inner exception is:
System.Transactions.TransactionException: The operation is not valid for the state of the transaction.
This makes sense because I have just switched off the database. However, why isn't this exception handled by my TryCatch activity?
EDIT 1: Some additional information. I run the workflow using the WorkflowApplication class. To better see what's going on, I specified the properties Aborted and OnUnhandledException. When the exception occurs, it goes directly to Aborted and OnUnhandledException is skipped (although this is clearly an unhandled exception).
EDIT 2: I enabled the debug log and this provides some additional insight. The 'custom database activities' successfully run to completion. The first event log entry that indicates that something is wrong is a Verbose level message: The runtime transaction has completed with the state 'Aborted'. Next I see an Information message: WorkflowInstance Id: 'dbd1ba5c-2d8a-428c-970d-21215d7e06d9' E2E Activity (not sure what this means). And the Information message after that is: Activity 'System.Activities.Statements.TransactionScope', DisplayName: 'Transaction for run immediately checks', InstanceId: '389' has completed in the 'Faulted' state.
After this message, I see that each parent (including the TryCatch activity) completes in the 'Faulted' state, ending with the abortion of my workflow.
EDIT 3: To be clear, everything works as expected when an exception occurs in any of the 'custom database activities'. The exception is caught and the workflow continues. It only goes wrong when the transaction can't commit at the end of the TransactionScope. See the following stacktrace that is logged from the Aborted callback:
at System.Transactions.TransactionStateInDoubt.Rollback(InternalTransaction tx, Exception e)
at System.Transactions.Transaction.Rollback(Exception e)
at System.Activities.Runtime.ActivityExecutor.CompleteTransactionWorkItem.HandleException(Exception exception)
If you follow the calls from TransactionScope.OnCompletion(...), eventually you will arrive at the ActivityExecutor class from the stacktrace.
Transactions commit asynchronously and after the fact. You can't react to a failure of the transaction to commit because of a problem at the resource manager level.
As you pointed out, you can deal with exceptions that occur in your activities. If you look at the tracking records for your workflow my guess is that you would see the TryCatch activity is closed prior to the transaction abort.
Many years ago when I was a program manager in the COM+ team I studied this issue because often people want a transactional component (or workflow) as in this case to be able to react to a transaction abort.
The async nature of the resolution of the transaction means that you simply cannot react to it in the component itself. The solution is to react in the caller which can then take some action.
The design assumption is that once a transaction has aborted, nothing about state aqcuired in the transaction can be safely used - it will all be discarded because the transaction is aborted.
So just to add to Ron's answer. Your only option here is to add the SqlWorkflowInstanceStore and drop a Persist activity just before the TransactionScope. When the transaction aborts the whole workflow will abort but the past saved state will still be in the persistence database and the workflow can be restarted from this previously saved state and execute the transaction again.
On a thread that is processing new data in the system, if the data is invalid I write a message in the event log, containing the Environment.StackTrace information.
Writing in the event log throws an exception with no text message
Message:
CallStack - at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
at System.Environment.get_StackTrace()
at <my method that writes in the event log>
Any ideas why this happens?
EDIT: I am interested in what can cause the Environment.StackTrace to throw exception in general, so that i can understand what is happening in my case
#anchandra I don't know if you have figured this out since, as this is now 4 years old.
However I would like to add as I just stumbled upon this myself.
So, why does Environment.StackTrace throws an exception?
First the most uninteresting answer:
As you can see in the MSDN reference to the property, it can throw an ArgumentOutOfRangeException if "The requested stack trace information is out of range.", note also that the executing context must have System.Security.Permissions.EnvironmentPermission.
Now what stumped me for a second:
It does NOT throw an exception! Yes, that is what was happening to me, it actually returned me a Stack Trace that started listing the call to Environment.StackTrace like "at System.Environment.get_StackTrace()" then it showed all the other calling methods.
Because I was logging this into an audit log, if you look at it you assume there is an exception occurring at the last frame of the stack, but that's not true, I was just happening to request a Stack Trace at that point and stick it in my error log, very dumb once I realized this.
You need to capture the stacktrace before moving onto a separate thread.
Stacktrace will only show you the frames up to the root of the thread.