IMPORTANT - Using dOOdads in an ASP.NET Application

All your dOOdad needs ...

IMPORTANT - Using dOOdads in an ASP.NET Application

Postby mike.griffin on Thu Dec 16, 2004 1:42 pm

The dOOdad transaction manager uses TLS or Thread Local Storage so that everything you do on a thread is protected by a transaction when you call BeginTransaction(). This is a real nice feature, however, IIS uses a thread pool to serve pages, when a request comes in, IIS pulls a thread out of the thread pool and executes the page, this thread however may have an abandoned dOOdad transaction in it. So, you need to reset the thread transaction before Page_Load, here's how, create a base page and make all of your web pages inherit from it:

C#
Code: Select all
public class BasePage : System.Web.UI.Page
{
   public BasePage()
   {
      this.Init +=new EventHandler(Page_Init);
   }

   private void Page_Init(System.Object sender, System.EventArgs e)
   {
      TransactionMgr.ThreadTransactionMgrReset();
   }
}

VB.NET
Code: Select all
Public Class MyPage
    Inherits System.Web.UI.Page

    Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
           TransactionMgr.ThreadTransactionMgrReset()
    End Sub

End Class


You will find having a base page can really help out anyway when you find that you need to add functionality to all of your pages.
Last edited by mike.griffin on Tue Jan 18, 2005 4:54 pm, edited 2 times in total.
User avatar
mike.griffin
Site Admin
 
Posts: 3290
Joined: Sat Apr 03, 2004 6:10 am
Location: Indianapolis, IN

Postby sbc on Thu Dec 16, 2004 3:08 pm

Think I will start using a base page. Is there a way of telling all pages to use this base class (i.e. via a web config file)? So will this prevent timeouts from occuring?
User avatar
sbc
Expert
 
Posts: 446
Joined: Sat Apr 03, 2004 6:10 am
Location: North East Lincolnshire, England

Postby mike.griffin on Thu Dec 16, 2004 3:10 pm

Not that I know of, you have to manually change thier inheritance in your code, just make you base page inherit from System.Web.UI.Page and all is well.
User avatar
mike.griffin
Site Admin
 
Posts: 3290
Joined: Sat Apr 03, 2004 6:10 am
Location: Indianapolis, IN

Postby sbc on Thu Dec 16, 2004 3:58 pm

Found that you can actually: http://msdn.microsoft.com/library/en-us ... ection.asp
In web.config:
Code: Select all
<configuration>
   <system.web>
      <pages pageBaseType=\"MyAssembly.MyPageClass, MyAssembly\" />
   </system.web>
</configuration>

You will still have to change all your code-behind files (as you often use: public class MyPage : System.Web.UI.Page, so change to public class MyPage : MyAssembly.MyPageClass)
Last edited by sbc on Fri Jun 17, 2005 4:26 pm, edited 1 time in total.
User avatar
sbc
Expert
 
Posts: 446
Joined: Sat Apr 03, 2004 6:10 am
Location: North East Lincolnshire, England

Postby heromull on Tue Jan 18, 2005 4:13 pm

I have a base page with the OnInit like this...

Code: Select all
      protected override void OnInit(EventArgs e)
      {
         MyGeneration.dOOdads.TransactionMgr.ThreadTransactionMgrReset();
         ValidatorCollection mySavedValidators = new ValidatorCollection();   
         CopyValidators(Page.Validators, mySavedValidators);
         BuildFrame();
         MoveControls();
         CopyValidators(mySavedValidators, Page.Validators);   
         base.OnInit(e);
      }   //protected override void OnInit



We're not using any transactions outside of the default that comes with .Save(). We are finding that if a user requests a page that performs several db queries and before the page completes that user closes the browser, subsequent users receive \"This SqlTransaction has completed; it is no longer usable.\"

The stack trace looks like this.
System.Data.SqlClient.SqlTransaction.Rollback() +115
MyGeneration.dOOdads.TransactionMgr.RollbackTransaction()
MyGeneration.dOOdads.TransactionMgr.ThreadTransactionMgrReset()
OLFNet.BasePage.OnInit(EventArgs e) +104
OLFNet.Logon.OnInit(EventArgs e) +57
etc...

Could this issue be related to dOOdads?
heromull
User avatar
heromull
Corporal
 
Posts: 15
Joined: Fri Aug 13, 2004 2:10 pm
Location: Atlanta, USA

Postby mike.griffin on Tue Jan 18, 2005 4:24 pm

Yes, that is related to the transaction manager, I'm not sure about your OnOnit() method, here's how it I use it:

Code: Select all
public class BasePage : System.Web.UI.Page
{
   public BasePage()
   {
      this.Init +=new EventHandler(Page_Init);
   }

   private void Page_Init(System.Object sender, System.EventArgs e)
   {
      TransactionMgr.ThreadTransactionMgrReset();
   }
}

Is there where you are calling it. I got that error during development if I tried accesses an abandoned transaction, it could be that your OnInit() is being called to late?

Also, do you access any objects in your global.asax.cs class?
User avatar
mike.griffin
Site Admin
 
Posts: 3290
Joined: Sat Apr 03, 2004 6:10 am
Location: Indianapolis, IN

Postby mike.griffin on Tue Jan 18, 2005 4:33 pm

Also, continued from above ...

This is the ThreadTransactionMgrReset() method

Code: Select all
public static void ThreadTransactionMgrReset()
{
   TransactionMgr txMgr = TransactionMgr.ThreadTransactionMgr();

   if(txMgr.txCount > 0 && txMgr.hasRolledBack == false)
   {
      txMgr.RollbackTransaction();
   }

   Thread.SetData(txMgrSlot, null);
}

What I'll do is put a try catch around it like so:

Code: Select all
public static void ThreadTransactionMgrReset()
{
   TransactionMgr txMgr = TransactionMgr.ThreadTransactionMgr();

   try
   {
      if(txMgr.txCount > 0 && txMgr.hasRolledBack == false)
      {
         txMgr.RollbackTransaction();
      }
   }
   catch {}

   Thread.SetData(txMgrSlot, null);
}


Maybe you can try it and see if it is the problem ...
User avatar
mike.griffin
Site Admin
 
Posts: 3290
Joined: Sat Apr 03, 2004 6:10 am
Location: Indianapolis, IN

Postby sbc on Tue Jan 18, 2005 4:42 pm

Would resetting during Page_Render help as well? I have had occasional issues with timouts (probably too many database calls). Any tips on page/user control caching and dOOdads (as I don't do any at the moment)? ToXml and FromXml probably can help here as well (although that may not be too secure if the data is sensitive - unless saving to memory rather than the disk makes that a non-issue).
User avatar
sbc
Expert
 
Posts: 446
Joined: Sat Apr 03, 2004 6:10 am
Location: North East Lincolnshire, England

Postby mgnoonan on Tue Jan 18, 2005 4:43 pm

Would it help to add ThreadTansactionMgrReset to global.asax? Perhaps in the Session_OnStart()?
Matt Noonan
EasyObjects.NET - The O/RM for the Enterprise Library
http://www.easyobjects.net
User avatar
mgnoonan
Expert
 
Posts: 1019
Joined: Tue Sep 14, 2004 3:17 am
Location: Springboro, OH

Postby mike.griffin on Tue Jan 18, 2005 4:49 pm

Would it help to add ThreadTansactionMgrReset to global.asax? Perhaps in the Session_OnStart()?


No, actually the thread that is running your global.asax code is not a thread from the thread pool, otherwise you could have put the code in the OnPageStart() method (or whatever it's called). Good suggestion but it wont work.

I think the fix I suggested will work
User avatar
mike.griffin
Site Admin
 
Posts: 3290
Joined: Sat Apr 03, 2004 6:10 am
Location: Indianapolis, IN

Postby heromull on Tue Jan 18, 2005 4:51 pm

Ahh, I think I understand. Here's how we're calling our BasePage's OnInit
This is in the OnInit of our individual .aspx pages.

Code: Select all
override protected void OnInit(EventArgs e)
{
   InitializeComponent();
   base.OnInit(e);
}


I take it that this is too late? I'll see if I can get your example in place.
heromull
User avatar
heromull
Corporal
 
Posts: 15
Joined: Fri Aug 13, 2004 2:10 pm
Location: Atlanta, USA

Postby mike.griffin on Tue Jan 18, 2005 4:52 pm

Ya, try using the code as I posted, I'll update the top of this link, I'm sorry. I'm also going to put that try/catch block in the transaction manager too for safety.
User avatar
mike.griffin
Site Admin
 
Posts: 3290
Joined: Sat Apr 03, 2004 6:10 am
Location: Indianapolis, IN

Postby heromull on Mon Jan 31, 2005 8:53 pm

It's been almost two weeks since we put these changes in (updated base page and try{} block around ThreadTransactionMgrReset) and all is well.

Thanks so much for the support!!
heromull
User avatar
heromull
Corporal
 
Posts: 15
Joined: Fri Aug 13, 2004 2:10 pm
Location: Atlanta, USA

Postby mike.griffin on Mon Jan 31, 2005 9:00 pm

I've made those changes in 1.1 too, thanx for the report.
User avatar
mike.griffin
Site Admin
 
Posts: 3290
Joined: Sat Apr 03, 2004 6:10 am
Location: Indianapolis, IN

Postby Mischa_k on Sun Feb 27, 2005 8:18 pm

Is there anyway to avoid the necesity of including extra code in the on page init ? or inheriting from a base class ?

Could this be solved with a checkbox or something while generating to make a asp.net or a winform output to make this go away ?
Mischa_k
Lieutenant Colonel
 
Posts: 94
Joined: Tue Aug 03, 2004 2:42 pm
Location: Holland

Postby mike.griffin on Sun Feb 27, 2005 8:41 pm

Yes, I use a base page, if you look at the classes at the top of this page I simply make a class like that and create my pages as usual in Visual Studio then change the class so that it inherits from BasePage instead of System.Web.UI.Page. But yes, in the end you still have to remember to do it.
User avatar
mike.griffin
Site Admin
 
Posts: 3290
Joined: Sat Apr 03, 2004 6:10 am
Location: Indianapolis, IN

Re:

Postby Mischa_k on Mon Feb 28, 2005 11:13 am

mike.griffin wrote:Yes, I use a base page, if you look at the classes at the top of this page I simply make a class like that and create my pages as usual in Visual Studio then change the class so that it inherits from BasePage instead of System.Web.UI.Page. But yes, in the end you still have to remember to do it.


Yup thats one thing, I would like to avoid...
It's just one more thing to do ... and my memory is far from perfect.
Mischa_k
Lieutenant Colonel
 
Posts: 94
Joined: Tue Aug 03, 2004 2:42 pm
Location: Holland

Postby vaporwareinc on Wed Jun 22, 2005 7:11 am

I have a problem in that I cannot modify my base page.

I am using a code generator (Code Charge Studio) for the GUI side of my project, and it doesn't allow this (unless I want to lose my round-trip development)

Can this thread problem be avoided by putting the TransactionMgr.ThreadTransactionMgrReset() in an overridden save() or New() in my concrete classes?

obviously I would do it after a Mybase.Save(), or before a Mybase.New()
but I need to know if this will avoid the problem?

of course in code I could just always call TransactionMgr.ThreadTransactionMgrReset()
after any Save, would that also work??

Any help would be appreciated,

-= Mark
Mark P Spencer
vaporwareinc
Lurker
 
Posts: 1
Joined: Wed Jun 22, 2005 6:53 am

Postby mike.griffin on Wed Jun 22, 2005 1:40 pm

Wow, if you were using MyGeneration for your UI you could actually edit your generated code and put our preserve region syntax, http://www.mygenerationsoftware.com/php ... .php?t=546

:roll: :roll:

They key is to either do it at the start of each page or at the end as you are suggestion, there might even be an event (and I think there is) that signifies the page is done executing, I would put it there if you can.
User avatar
mike.griffin
Site Admin
 
Posts: 3290
Joined: Sat Apr 03, 2004 6:10 am
Location: Indianapolis, IN

Re:

Postby Mischa_k on Wed Jun 22, 2005 2:03 pm

mike.griffin wrote:Wow, if you were using MyGeneration for your UI you
They key is to either do it at the start of each page or at the end as you are suggestion, there might even be an event (and I think there is) that signifies the page is done executing, I would put it there if you can.


page_prerender
or maybe even
page_unload
Mischa_k
Lieutenant Colonel
 
Posts: 94
Joined: Tue Aug 03, 2004 2:42 pm
Location: Holland

Next

Return to dOOdads - MyGeneration's .NET Architecture

Who is online

Users browsing this forum: No registered users and 1 guest

cron