我尝试在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
类型,具体取决于CompletedSynchronously
中SqlCommandAsyncResult
的值{1}}课程。
设置CompletedSynchronously = false
会导致我的代码失败,因为我无法访问SqlCommand而设置CompletedSynchronously = true
代码就像魅力一样,但我有一种奇怪的感觉,可能会出现问题。
我感谢任何帮助,指导和示例代码如何使这些代码正常工作,更重要的是帮助我理解手头的问题。
非常感谢你。 扬
答案 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