异步数据库操作

时间:2014-08-28 15:16:01

标签: c# asynchronous workflow-foundation-4 enterprise-library

我的工作流程托管在IIS中。并且每个工作流都继承自asynccodeactivity。在BeginExecute中,我调用command.Beginxxx,最后执行i调用EndExecutexxx。我正在使用数据库访问块(DAAB)。

protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
    {
        DbCommand command = null;
        DbConnection dbConnection = null;
        entlib.Database database;

        try
        {
            database = EnterpriseLibraryContainer.Current.GetInstance<entlib.Database>(DatabaseName.Get(context));
            dbConnection = database.CreateConnection();
            command = dbConnection.CreateCommand();
            command.CommandText = CommandText.Get(context);
            command.CommandType = CommandType.Get(context);

            //have removed few assignments here

            context.UserState = new AsyncDbState(database, command);
        }
        catch (Exception e)
        {
            if (command != null)
                command.Dispose();
            if (dbConnection != null)
                dbConnection.Dispose();

            throw e;
        }

        return (database.Beginxxx(command, callback, state));
    }


    protected override TResult EndExecute(AsyncCodeActivityContext context, IAsyncResult iResult)
    {
        TResult result = default(TResult);

        var userState = context.UserState as AsyncDbState;

            try
            {
                result = (TResult)userState.Database.Endxxx(iResult);
            }
            finally
            {
                if (null != userState && null != userState.Command)
                    userState.Command.Dispose();
            }

        return result;
    }

偶尔会在事件日志中抛出错误并终止整个应用程序池。 在@Will发表评论之后,我确实陷入了内部异常并注意到实际发生的错误

在不同活动的BeginExecute中,继承自asyncnativeactivity,我有

 var task = AsyncFactory<IDataReader>.Action(() => ExecuteMdxQuery(connectionStringSettings, mdxQuery, commandTimeout, cancellationToken), cancellationToken);                        

                    return AsyncFactory<IDataReader>.ToBegin(task, callback, state);

and AsyncFactory looks like this 

 public static Task<TResult> Action(Func<TResult> actionMethod,CancellationToken token)
    {
        TaskFactory factory = new TaskFactory();
        //TaskFactory factory = new TaskFactory(scheduler);
        return factory.StartNew<TResult>(() => actionMethod(), token);   
        }
  public static IAsyncResult ToBegin(Task<TResult> task, AsyncCallback callback, object state)
    {
        var tcs = new TaskCompletionSource<TResult>(state);
        var continuationTask = task.ContinueWith(t =>
        {
            if (task.IsFaulted)
            {
                tcs.TrySetException(task.Exception.InnerExceptions);
            }
            else if (task.IsCanceled)
            {
                tcs.TrySetCanceled();
            }
            else
            {
                tcs.TrySetResult(task.Result);
            }

发生了未处理的异常,并且该过程已终止。

发生了未处理的异常,并且该过程已终止。

申请ID:/ LM / W3SVC / 1 / ROOT / workflowservice

流程ID:7140

异常:System.AggregateException

消息:通过等待任务或访问其异常属性,未观察到任务的异常。结果,终结器线程重新抛出了未观察到的异常。

StackTrace:在System.Threading.Tasks.TaskExceptionHolder.Finalize()

InnerException:Microsoft.AnalysisServices.AdomdClient.AdomdErrorResponseException

消息:服务器:当前操作已取消,因为事务中的另一个操作失败。

StackTrace:at Microsoft.AnalysisServices.AdomdClient.AdomdConnection.XmlaClientProvider.Microsoft.AnalysisServices.AdomdClient.IExecuteProvider.ExecuteTabular(CommandBehavior behavior,ICommandContentProvider contentProvider,AdomdPropertyCollection commandProperties,IDataParameterCollection parameters)    在Microsoft.AnalysisServices.AdomdClient.AdomdCommand.ExecuteReader(CommandBehavior行为)    at WorkflowActivity.AsyncExecuteSafeReader.ExecuteMdxQuery(String connectionStringName,String mdxQuery,Nullable 1 commandTimeout, CancellationToken cancellationToken) in d:\B\69\Sources\Infrastructure\WorkflowActivity\AsyncExecuteSafeReader.cs:line 222 at AsyncExecuteSafeReader.ExecuteMdxQuery(String connectionStringName, String mdxQuery, Nullable 1 commandTimeout,CancellationToken cancellationToken)在d:\ B \ 69 \ Sources \ Infrastructure \ WorkflowActivity \ AsyncExecuteSafeReader.cs:第239行    在WorkflowActivity.AsyncExecuteSafeReader。&lt;&gt; c__DisplayClassd.b__a()在d:\ B \ 69 \ Sources \ Infrastructure \ WorkflowActivity \ AsyncExecuteSafeReader.cs:第180行    在System.Threading.Tasks.Task`1.InvokeFuture(Object futureAsObj)    在System.Threading.Tasks.Task.Execute()

2 个答案:

答案 0 :(得分:2)

第一个提示是这种情况发生在IIS中。虽然在您可能遇到由多线程引起的问题时,应用程序通常会清楚,但在IIS中并非如此。

IIS中的每个请求都由不同的线程提供服务。任何共享实例都会受到多个线程的攻击。如果你不期待它,这往往是坏消息。

所以我的第一个猜测(不得不猜测,因为你的异常调用堆栈被切断了;后面会有更多内容)是你在不同的线程中使用线程不安全的代码。我怀疑它集中在EnterpriseLibraryContainer.Current.GetInstance,因为如果它不存储每个线程的实例,它将在线程之间共享相同的实例。您必须检查代码或文档。最简单的测试方法是使用&#34;制作对象ID&#34;在观察窗口中,然后在两个不同的线程中比较EnterpriseLibraryContainer.Current.GetInstance的结果。

有关此情况下最佳做法的详细信息,请see this answer

重新检查调用堆栈,它似乎仍然是一个多线程错误,但似乎问题是多个线程试图完成两个不同的Task的执行。

  

消息:操作已完成。
  StackTrace:在System.Activities.AsyncOperationContext.ShouldComplete()
  (剪断)

某处某处正在尝试完成Task的执行,但它已经完成。就像在,一个线程击败另一个完成异步操作。

此时,如果没有异常的完整堆栈跟踪,就无法确定实际问题是什么以及发生了什么。获取此信息的最佳方法是在代码中第一次捕获异常并在其上调用ToString(),或使用&#34;复制到剪贴板&#34;异常帮助器对话框上的链接(做同样的事情,将其复制到剪贴板)。这很重要,因为您可以获得以下信息

  1. 例外类型
  2. 异常消息
  3. 堆栈跟踪
  4. 不仅仅是针对您捕获的异常,而是针对此异常所包含的每个.InnerException经常隐藏您的真正问题。< / strong>

    而且,在这种情况下,当您这样做时,您就能够确定代码遇到重入问题的位置。

答案 1 :(得分:0)

@Will,看起来连接字符串中的Mars = false已经解决了它。无法复制它。 理论是 - 查询返回结果。和结束执行被调用。但它还返回了另一个结果集?这就是调用回调的原因。但是当时已经调用了end execute。但话说回来,它是零星的。如果这个理论是正确的,我的理解是它可能一直都失败了。 到目前为止还没有崩溃。还有很少有行计数的程序。 我很感激你花时间评论并分享你的理论。我学到了很多东西。