如何避免ASP.NET SqlServer会话干扰环境Transaction-Per-Request?

时间:2010-05-20 11:32:23

标签: asp.net session-state transactions

我正在尝试在每个请求的事务模式中使用事务范围。所以我有一个http模块(简化):

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();
    }
}

然后,在我的web.config中,我有:

<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"/>

现在,在看似随机率的情况下,大约有十分之一的页面给出了以下错误:

[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

我(我想)理解的是,有时会在我的业务事务中登记与ASP.NET会话数据库的连接,并且在我的业务事务首先完成时会出现此错误。

有一些问题:

  • 我不认为会话状态的事务应该与我的业务事务相同。这是两个不同的问题。
  • 它使事务自动升级到分布式(MSDTC),这会影响我的性能。

    如何将业务事务与ASP.NET会话分离?

    提前致谢,

    于连

2 个答案:

答案 0 :(得分:2)

这是一个Necro-Answering,但是问题的答案,以防万一其他人在谷歌搜索时随机发现这个问题是将Enlist=False添加到SqlServerSessionState connection string

由于奇怪的时间安排,用于检索会话的连接有时可以在环境事务中登记,即使您可能更愿意不这样做。

在连接字符串上设置Enlist=False可确保您的会话状态连接不会获取环境事务,从而导致一个好的快速事务被提升为较慢的分布式事务。

答案 1 :(得分:0)

我不完全确定您的代码是如何工作的,但您可以像这样抑制环境事务,这可能有所帮助:

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
}