我嘗試在WCF數據服務中實現'AsyncPattern'。我在界面中定義了兩種方法BeginGetExperiments(...)和EndGetExperiments(...),並實現瞭如下所示的方法。服務器端AsyncPattern調用SQL服務器
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的狀態必須是傳遞給您的Begin調用的狀態參數。」
所以我嘗試使用IAsyncResult將SqlCommand傳遞給EndGetExperiments
。這裏,我不明白的是,在EndGetExperiments
中,可變結果是類型IAsyncResult
或類型SqlCommandAsyncResult
,具體取決於SqlCommandAsyncResult
類中的CompletedSynchronously
的值。 設置CompletedSynchronously = false
使我的代碼失敗,因爲我不能訪問SqlCommand,而設置CompletedSynchronously = true
代碼的作品就像一個魅力,但我有一種奇怪的感覺,可能會出現問題。
感謝任何幫助,指導和示例代碼如何使這個代碼工作,甚至更重要的是幫助我瞭解手頭的問題。
非常感謝。 Jan
感謝@tonyjy的輸入,但是您的建議模式與'[OperationContractAttribute(...)中的BeginMyMethod(...)EndMyMethod(...) AsyncPattern = true)]'wcf數據服務? – jahu 2011-04-04 13:38:47
我想這取決於你想達到的目標。如果您正在嘗試實現您的客戶端在調用WCF時不阻塞地運行。服務器可以實現爲同步,客戶端可以使用異步。任務將在客戶端非常有用,無論是TreadPool還是ConcurrentContext。 –
tonyjy
2011-04-04 14:36:33
再次感謝。我很困惑。我上面發佈的代碼顯然在服務器端運行。我試圖弄清楚的是,如何使用最佳實踐技術來實現wcf數據服務的**服務器端**,以便從SQl服務器獲取一些數據,然後將它們轉發給客戶端。我試着按照這裏提供的'AsyncPattern = true':[link](http://msdn.microsoft.com/en-us/library/ms731177.aspx)。到目前爲止,我只是在談論服務器端。 – jahu 2011-04-04 14:51:21