C# - TransactionScope - TransactionAbortedException - The transaction has aborted - c#

I've code like that:
class Importer
{
private DatabaseContext m_context;
public: Importer()
{
m_context = new DatabaseContext();
m_context.CommandTimeout = 5400; //This is seconds
}
public bool Import (ref String p_outErrorMsg)
{
List<SomeData> dataToImport = new List<SomeData>();
getSomeData(ref dataTiImport);
bool result = false;
try
{
using(TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, new TimeSpan(2, 0, 0)))
{ //Two hours timeout
result = importDatas(dataToImport);
if (result == true)
{
scope.Complete();
}
}
}
catch (TransactionAbortedException ex)
{
p_outErrorMsg = String.Format("TransactionAbortedException Message: {0}", ex.Message);
}
catch (ApplicationException ex)
{
p_outErrorMsg = String.Format("ApplicationException Message: {0}", ex.Message);
}
}
bool importDatas(List<SomeData> p_DataToImport)
{
foreach (SomeData data in p_DataToImport)
{ //There can be somehitg about 3000 iterations
if (!importSimpleData(data))
{
return false;
}
return true;
}
}
bool importSimpleData(SomeData p_Data)
{
//creation some object o1
try
{
m_context.objetc1s.InsertOnSubmit(o1);
m_context.SubmitChanges();
}
catch (Exception e)
{
//Error handlig
return false
}
//creation some object o2
o2.id_o1 = o1.id_o1;
try
{
m_context.objetc2s.InsertOnSubmit(o2);
m_context.SubmitChanges();
}
catch (Exception e)
{
//Error handlig
return false
}
//creation some object o3
o3.id_o2 = o2.id_o2;
try
{
m_context.objetc3s.InsertOnSubmit(o3);
m_context.SubmitChanges();
}
catch (Exception e)
{
//Error handlig
return false
}
//creation some object o4
o4.id_o1 = o1.id_o1;
try
{
m_context.objetc4s.InsertOnSubmit(o4);
m_context.SubmitChanges();
}
catch (Exception e)
{
//Error handlig
return false
}
return true;
}
}
And if List has 500 records, all is writing fine.
But when the list is near to 1000, I've always exception:
TransactionAbortedException.Message = "the transaction has aborted".
Firstly I think that timeout was to small so I did introduce to code this two lines:
...
m_context.CommandTimeout = 5400; //This is seconds (1.5 hour)
...
using(TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, new TimeSpan(2, 0, 0))) { //Two hours timeout
...
As you can see in presented above code.
The same exception still occurs, did I miss something?
What do I do wrongly?
I have to add that data base is remote (not local)
Thanks in advance for the help!

I'd have to dig up the documentation again, but setting a transaction timeout to 2 hours may not be happening for you. There is a cap on how long the transaction timeout can be that comes down through machine.config and if you specify more than that cap, it quietly ignores you.
I ran into this a long time ago, and found a reflection-based way to tweak that setting here by Matt Honeycutt to make sure you're really getting the timeout you specify.

It seems that importSimpleData fails on some row and importData returns false. In such case you don't call scope.Complete() and it's the reason why transaction rolls back.

Related

Transactions - Entity Framework 5

I am experiencing a "Transaction timeout exceeded" issue in the code snippet below
using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew,
new TransactionOptions { IsolationLevel = IsolationLevel.ReadUncommitted, Timeout = new TimeSpan(1, 0, 0) }))
{
try
{
segregationAssignment = new SegregationAssignment(dbContext).Assign(rmaU);
dbContext.SaveChanges();
scope.Complete();
scope.Dispose();
}
catch (DbUpdateException eb)
{
scope.Dispose();
return RedirectToAction("Details", details).WithErrorMessage(string.Format(Validations.not_possible_to_operation,
details.IsConfirmSegregate ? Buttons.segregate.ToLower() : Buttons.refuse.ToLower(), Models.rma_u));
}
catch (Exception ex)
{
scope.Dispose();
return RedirectToAction("Details", details).WithErrorMessage(string.Format(Validations.not_possible_to_operation,
details.IsConfirmSegregate ? Buttons.segregate.ToLower() : Buttons.refuse.ToLower(), Models.rma_u));
}
}
Inside it we have some additions of objects in context in the Assign method, only that. I do not understand why you're giving timeout in a process that takes a maximum of 10 minutes.
If you can help me, I'll be grateful. We are using version 5 of entity.

Overriding SaveChangesAsync when enclosed inside TransactionScope?

I'm fairly new to EF transactions, this is the code that is used for saving
public bool Save(TbArea area, bool isNew, out string errMsg)
{
try
{
errMsg = string.Empty;
using (var oScope = new System.Transactions.TransactionScope(TransactionScopeOption.Required, TimeSpan.FromSeconds(120)))
{
try
{
TbArea oEntity = oContext.TbArea.Where(a => a.AreaCode == area.AreaCode && a.CompanyId == MainClass.SystemCompanyId).FirstOrDefault();
if (oEntity != null)
{
if (isNew) { errMsg = Resources.ResSales.MsgRecordCodeDublicated; return false; }
oContext.TbArea.Attach(oEntity);
oContext.Entry(oEntity).CurrentValues.SetValues(area);
}
else
{
if (!isNew) { errMsg = Resources.ResSales.MsgRecordNotFoundInDB; return false; }
oContext.TbArea.Add(area);
}
oContext.SaveChangesAsync();
oScope.Complete();
return true;
}
catch (Exception ex)
{
oScope.Dispose();
errMsg = ex.Message;
return false;
}
}
I'm overriding SaveChangesAsync
so that I can save the ChangeTracker.Entries into the database.
this is a portion of the code:
dbContext.AcceptAllChanges();
logsSet.AddRange(audits);
int result = 0;
try
{
result = await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
//scope.Complete(); there was a transaction that I commented out, I thought it might overlaps the original transaction!
return result;
}
catch (Exception ex)
{
var m = ex.Message;
return result;
}
When I save an item, I get the error :
the transaction has aborted
when I remove the transaction scope the saving happens normally!
Your code is marking the transaction complete before the changes have finished saving:
oContext.SaveChangesAsync();
oScope.Complete();
You need to use await:
await oContext.SaveChangesAsync();
oScope.Complete();
If you're in a context where await can resume on a different thread, you'll probably also need to specify TransactionScopeAsyncFlowOption.Enabled.

Inexplicable NullReferenceException that only occurs in production

We have an ASP.NET website running which throws a NullReference-exception along with a stacktrace and a line number that is simply impossible. And I can't make heads nor tails from it myself.
It says:
Exception at ReportService.GetReport(String reportType) in ReportService.cs:line 1458
which is funny, because that is this line:
var exports = new List<ReportExport>();
Thanks to the (very short) stacktrace, I can see that the error is triggered in the GetReport-function and not in the "GetAllUsers" or "GetAllUsersWithFilter" functions, because I would receive a different error message in my e-mailbox or I would see it pop up in the stacktrace.
So I suspect the line number is wrong, in which case there is only one other possibility and that is this line:
foreach (var userProfile in users) {
exports.Add(CreateUserProfile(userProfile));
}
But how could users ever be null?
Full (albeit simplified) code right here:
public function IList<ReportExport> GetReport(string reportType) {
try {
IQueryable<UserProfile> users = null;
switch (reportType) {
case "abc" :
users = GetAllUsersWithFilter();
break;
case default:
users = GetAllUsers();
break;
}
var exports = new List<ReportExport>();
foreach (var userProfile in users) {
exports.Add(CreateUserProfile(userProfile));
}
} catch (Exception ex) {
SendErrorMail("GetReport has failed", ex); /* I receive this error mail */
}
function IQueryable<UserProfile> GetAllUsers() {
try {
return dbContext.Users.Where(x => x.IsRegistered == true);
} catch (Exception ex) {
SendErrorMail("GetAllUsers", ex); /* I don't receive this e-mail */
return null;
}
}
function IQueryable<UserProfile> GetAllUsersWithFilter() {
try {
return GetAllUsers().Where(x => x.ExtraFilter == true);
} catch (Exception ex) {
SendErrorMail("GetAllUsersWithFilter", ex); /* I don't receive this e-mail */
}
}
function int GetNumberOfSessions(int userId) {
try {
return dbContext.Sessions.Count(x => x.UserId == userId);
} catch (Exception ex) {
SendErrorMail("GetNumberOfSessions", ex); /* I don't receive this e-mail */
}
}
function ReportExport CreateUserExport(UserProfile user) {
try {
var cnt = GetNumberOfSessions(user.Id);
return new ReportExport() {
UserId = user.Id,
NumberOfSessions = cnt
}
} catch (Exception ex) {
SendErrorMail(("CreateUserExport", ex);
}
}
If you are in production then you might be running with optimizations switched on - therefore the line number will be wrong.
But how could users ever be null?
But you are catching the Exception then returning null. You are relying on returning data - which may not be the case in GetAllUsers.
function IQueryable<UserProfile> GetAllUsers() {
try {
return dbContext.Users.Where(x => x.IsRegistered == true);
} catch (Exception ex) {
SendErrorMail("GetAllUsers", ex); /* I don't receive this e-mail */
return null;
}
}

Returning result in nested try catch block

I am implementing some performance counters and I would like to know your opinion.
The question is should I declare response and return it outside try block or Is it OK to return it directly in the try block. Is there a difference and If so, what sample code is valid (if any).
With best regards, no9.
public string TestMethod(string document)
{
try
{
WebService ws = new WebService();
string response = null;
var startTime = PerformanceCounter.GetPerformanceCounterStartTimeHandle();
try
{
response = ws.InsertDocument(document);
}
catch (Exception ex)
{
PerformanceCounterHelper.Increment(PerformanceCounterEnum.NumberOfExternalWsCallsExceptionOnSec);
throw;
}
finally
{
PerformanceCounterHelper.IncrementPerformanceCounterByElapsedTime(PerformanceCounterEnum.DurationOfExternalCallsInSec, startTime);
PerformanceCounterHelper.Increment(PerformanceCounterEnum.NumberOfExternalCallsOnSec);
}
return response;
}
catch (Exception ex)
{
log.EventError(ex);
throw new DocumentGeneralException();
}
}
versus:
public string TestMethod(string document)
{
try
{
WebService ws = new WebService();
var startTime = PerformanceCounter.GetPerformanceCounterStartTimeHandle();
try
{
return ws.InsertDocument(document);
}
catch (Exception ex)
{
PerformanceCounterHelper.Increment(PerformanceCounterEnum.NumberOfExternalWsCallsExceptionOnSec);
throw;
}
finally
{
PerformanceCounterHelper.IncrementPerformanceCounterByElapsedTime(PerformanceCounterEnum.DurationOfExternalCallsInSec, startTime);
PerformanceCounterHelper.Increment(PerformanceCounterEnum.NumberOfExternalCallsOnSec);
}
}
catch (Exception ex)
{
log.EventError(ex);
throw new DocumentGeneralException();
}
}
As long as there isn't a difference because of not exiting (i.e. it runs additional/different code), then the code is identical. Actually, at the IL level it is illegal to ret from inside a try/catch, so one of the things the compiler does is to do exactly what you have done: introduce a local, assign the local inside the try/catch, then return that value when outside the try/catch.
Basically, go with whatever is simplest and most convenient to read. In your case, I would say "the first one".

Null values while updating DB in Parallel.Foreach

I use following script to get data from external service and store in dB. In certain rare cases less than 1% records gets updated with null values. In below code, the "re.status=fail" we see null. let us know if any thots.
public void ProcessEnquiries()
{
List<req> request = new List<req>();
var options = new ParallelOptions { MaxDegreeOfParallelism = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["MaxDegreeOfParallelism"]) };
try
{
Parallel.ForEach(request, options, currentRequest =>
{
ProcessedRequest processedRequest = null;
processedRequest = CommunicateToWS(currentRequest); // Here we call to webservice
});
}
catch (AggregateException exception)
{
foreach (Exception ex in exception.InnerExceptions)
{
// Handle Exception
}
}
}
public ProcessedRequest CommunicateToWS(req objReq)
{
ProcessedRequest re = new ProcessedRequest();
using (WebCall obj = new WebCall())
{
re.no = refnu;
try
{
retval = obj.getValue(inval);
objProxy.Close();
//get data
// parse and store to DB
}
catch (Exception e)
{
re.status = "fail";
//update DB that request has failed
//Handle Exception
obj.Close();
}
}
}

Categories

Resources