服务器端AsyncPattern调用SQL Server

时间:2011-04-04 13:05:01

标签: c# asynchronous wcf-data-services

我尝试在WCF数据服务中实现'AsyncPattern'。我在界面中定义了两个方法BeginGetExperiments(...)和EndGetExperiments(...),并实现了如下所示的方法。

public class GmdProfileService : IGmdProfileService
{
 IAsyncResult IGmdProfileService.BeginGetExperiments(AsyncCallback callback, object state)
    {
        //IAsyncResult res =  Experiment.GetExperimentsAsync(callback, state, Properties.Settings.Default.gmdConnectionString);
        //return res;

        System.Data.SqlClient.SqlConnectionStringBuilder csb = new System.Data.SqlClient.SqlConnectionStringBuilder(Properties.Settings.Default.gmdConnectionString);
        csb.AsynchronousProcessing = true;
        System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(csb.ConnectionString);
        conn.Open();
        System.Data.SqlClient.SqlCommand cmd = conn.CreateCommand();
        cmd = conn.CreateCommand();
        cmd.CommandText = "SELECT id, name, comment, date, doi FROM tf.TagList WITH(NOLOCK) WHERE proprietary=0;";
        cmd.CommandType = System.Data.CommandType.Text;
        return new SqlCommandAsyncResult(cmd, callback, state);
    }

    public List<Experiment> EndGetExperiments(IAsyncResult result)
    {
        List<Experiment> res = new List<Experiment>();
        SqlCommandAsyncResult myresult = result as SqlCommandAsyncResult;
        using (System.Data.SqlClient.SqlDataReader reader = myresult.cmd.EndExecuteReader(myresult.originalState as IAsyncResult))
        {
            try
            {
                while (reader.Read())
                {
                    res.Add(new Experiment(reader));
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                // Closing the reader also closes the connection, because this reader was created using the CommandBehavior.CloseConnection value.
                if (reader != null)
                {
                    reader.Close();
                }
            }
        }
        return res;
    }

BeginGetExperiments返回实现SqlCommandAsyncResult接口的类IAsyncResult,此外还包含对SqlCommand的引用以供日后访问。

public class SqlCommandAsyncResult : IAsyncResult
{
    public SqlCommand cmd { get; private set; }
    public IAsyncResult originalState { get; private set; }

    public SqlCommandAsyncResult(SqlCommand cmd, AsyncCallback callback, object state)
    {
        this.cmd = cmd;
        this.originalState = cmd.BeginExecuteReader(callback,
            state,
            System.Data.CommandBehavior.SequentialAccess |  // doesn't load whole column into memory
            System.Data.CommandBehavior.CloseConnection   // close connection immediately after read
            );
    }

    public object AsyncState
    {
        get { return originalState.AsyncState; }
    }

    public WaitHandle AsyncWaitHandle
    {
        get { return originalState.AsyncWaitHandle; }
    }

    public bool CompletedSynchronously
    {
        get { return false; }
    }

    public bool IsCompleted
    {
        get { return AsyncWaitHandle.WaitOne(0); }
    }
}

我面临的困难是EndGetExperiments方法。我不知道如何访问SqlCommand来致电EndExecuteReader(...)。 通常我会使用BeginExecutereader中的状态对象来传递命令。但如果我这样做,我得到例外: “IAsyncResult的State必须是传递给Begin调用的状态参数。”

所以我尝试使用IAsyncResult将SqlCommand传递给EndGetExperiments。在这里,我不明白的一点是,在EndGetExperiments中,变量结果是IAsyncResult类型或SqlCommandAsyncResult类型,具体取决于CompletedSynchronouslySqlCommandAsyncResult的值{1}}课程。 设置CompletedSynchronously = false会导致我的代码失败,因为我无法访问SqlCommand而设置CompletedSynchronously = true代码就像魅力一样,但我有一种奇怪的感觉,可能会出现问题。

我感谢任何帮助,指导和示例代码如何使这些代码正常工作,更重要的是帮助我理解手头的问题。

非常感谢你。 扬

2 个答案:

答案 0 :(得分:1)

如果您使用的是C#4.0。使用Task<T>实现这一点可能会更容易。 Task<T>将执行Func<T>,其中T是返回值。您可以定义一个获取Parent.Result的延续任务。我知道这个答案可能不是你想要的。但请将此视为替代方案。代码更清晰,易于维护,易于调试(使用任务并行窗口,并行堆栈等)。

答案 1 :(得分:1)

今天,WCF数据服务不支持服务器上的异步处理。请在此投票/添加功能请求:http://data.uservoice.com/forums/72027-wcf-data-services-feature-suggestions/topics/72603-wcf-data-services-feature-suggestions