2010-05-20 5 views
1

J'essaie d'utiliser une étendue de transaction dans un modèle de transaction par requête. J'ai donc un module http qui ne (simplifié):Comment éviter une session ASP.NET SqlServer d'interférer avec la Transaction-Per-Request ambiante?

private void Application_BeginRequest(object sender, EventArgs e) 
{ 
    var scope = new TransactionScope(TransactionScopeOption.RequiresNew); 
    PutScopeInHttpContext(scope); 
} 

private void Application_EndRequest(object sender, EventArgs e) 
{ 
    var scope = GetScopeFromHttpContext(); 
    try 
    { 
     if (HttpContext.Current.Error == null) 
     { 
      scope.Complete(); 
     } 
    } 
    finally 
    { 
     scope.Dispose(); 
    } 
} 

Puis, dans mon web.config, je:

<httpModules> 
    <clear/> 
    <add name="OutputCache" type="System.Web.Caching.OutputCacheModule"/> 
    <add name="Session" type="System.Web.SessionState.SessionStateModule"/> 
    <add name="Profile" type="System.Web.Profile.ProfileModule"/> 
    <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> 
    <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> 
    <add name="TransactionPerRequestWebModule" type="Acme.Web.TransactionPerRequestWebModule, Acme.Web"/> 
</httpModules> 
<sessionState mode="SQLServer" sqlConnectionString="Data Source=localhost\SQLEXPRESS;Integrated Security=SSPI;" cookieless="false" timeout="360"/> 

Maintenant, à ce qui apparaît comme taux au hasard, à peu près 1 page sur dix me donne l'erreur suivante:

[SqlException (0x80131904): Distributed transaction completed. Either enlist this session in a new transaction or the NULL transaction.] 
    System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) +1951450 
    System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) +4849003 
    System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj) +194 
    System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) +2394 
    System.Data.SqlClient.SqlDataReader.ConsumeMetaData() +33 
    System.Data.SqlClient.SqlDataReader.get_MetaData() +83 
    System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) +297 
    System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async) +954 
    System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) +162 
    System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) +32 
    System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) +141 
    System.Data.SqlClient.SqlCommand.ExecuteReader() +89 
    System.Web.SessionState.SqlSessionStateStore.DoGet(HttpContext context, String id, Boolean getExclusive, Boolean& locked, TimeSpan& lockAge, Object& lockId, SessionStateActions& actionFlags) +516 

[HttpException (0x80004005): Unable to connect to SQL Server session database.] 
    System.Web.SessionState.SqlSessionStateStore.ThrowSqlConnectionException(SqlConnection conn, Exception e) +229 
    System.Web.SessionState.SqlSessionStateStore.DoGet(HttpContext context, String id, Boolean getExclusive, Boolean& locked, TimeSpan& lockAge, Object& lockId, SessionStateActions& actionFlags) +649 
    System.Web.SessionState.SqlSessionStateStore.GetItemExclusive(HttpContext context, String id, Boolean& locked, TimeSpan& lockAge, Object& lockId, SessionStateActions& actionFlags) +48 
    System.Web.SessionState.SessionStateModule.GetSessionStateItem() +117 
    System.Web.SessionState.SessionStateModule.BeginAcquireState(Object source, EventArgs e, AsyncCallback cb, Object extraData) +487 
    System.Web.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +66 
    System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155 

ce que je (crois) comprendre est que la connexion à la base de données de session ASP.NET est parfois enrôlé dans ma transaction commerciale, et je reçois cette erreur lorsque ma transaction commerciale je s terminer en premier.

Il y a quelques problème avec ça:

  • Je ne pense pas que la transaction pour l'état de session doit être le même que mon seul d'affaires. Ce sont deux préoccupations distinctes.
  • Il fait automatiquement remonter la transaction à une transaction distribuée (MSDTC), ce qui affecte mes performances. Comment puis-je découpler ma transaction commerciale de la session ASP.NET?

    Merci à l'avance,

    Julien

Répondre

0

Je ne suis pas tout à fait sûr de la façon dont votre code fonctionne, mais vous pouvez supprimer la transaction ambiante comme celui-ci, ce qui peut aider:

using(TransactionScope scope1 = new TransactionScope()) 
{ 
    try 
    { 
      //Start of non-transactional section 
      using(TransactionScope scope2 = new 
      TransactionScope(TransactionScopeOption.Suppress)) 
      { 
       //Do non-transactional work here 
      } 
      //Restores ambient transaction here 
    } 
    catch 
    {} 
    //Rest of scope1 
} 
+0

Merci pour votre réponse, Balazs. Je n'ai peut-être pas été clair. J'ai besoin d'une transaction commerciale, donc je ne veux pas la supprimer. C'est juste que j'ai besoin d'être différent de celui de la session ASP.NET. – Julien

+0

Il ne serait supprimé que dans le cadre de ce bloc d'utilisation interne. Alors, faites ce que vous avez à faire dans ce bloc. Le travail lié à la session serait toujours couvert par une transaction (scope2). Cependant, une défaillance dans la transaction interne n'affecterait pas la transaction externe. C'est tout ce que fait l'option "Supprimer". Cela provoque simplement l'ignorance de ce bloc de code par la portée de transaction contenant. Est-ce que je ne comprends toujours pas votre question? – balazs

2

Ceci est un Necro-Réponse, mais la réponse à la question au cas où quelqu'un d'autre vient à travers cela au hasard tandis que Googling est d'ajouter Enlist=False au SqlServerSessionState connection string.

En raison d'un timing impair, la connexion utilisée pour récupérer la session peut parfois s'enrôler dans une transaction ambiante, même si vous préféreriez probablement que ce ne soit pas le cas.

La définition de Enlist=False sur la chaîne de connexion garantit que vos connexions d'état de session n'entraîneront pas la transaction ambiante et provoqueront ainsi une transaction rapide agréable à promouvoir vers une transaction distribuée plus lente.