2011-12-06 63 views
3

我有許多連接到它的webservice。 我用這個代碼:如何在ASP.NET webservice中執行SQL事務異步

IAsyncResult result = sqlCommand.BeginExecuteNonQuery(); 
while (!result.IsCompleted) 
{ 
    System.Threading.Thread.Sleep(500); 
} 
sqlCommand.EndExecuteNonQuery(result); 

我覺得這不是一個最好的方法,因爲我叫Sleep()。 PS。這種方法將是Web Service與服務器

UPDATE2的減速性能: 我試着描述我的代碼更多: 我有Web客戶端和2個事件(ProgressChangedDownloadCompleted

[WebMethod] 
public void DonwloadFromRemoteServer(string uniqueId, string url) 
{ 
    if (!Directory.Exists(uniqueId)) 
     Directory.CreateDirectory(uniqueId); 

    WebClient wc = new WebClient(); 

    wc.DownloadProgressChanged += (sender, args) => wc_DownloadProgressChanged(sender, args, uniqueId, Path.GetFileName(url)); 

    wc.DownloadFileCompleted += (sender, args) => wc_DownloadFileCompleted(sender, args, uniqueId, Path.GetFileName(url)); 
    wc.DownloadFileAsync(new Uri(url), String.Format("{0}\\{1}", uniqueId, Path.GetFileName(url))); 
} 

void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e, string uniqueId, string fileName) 
{ 
    SqlConnection connection = new SqlConnection("Data Source=.\\SQLSERVER;Initial Catalog=XRingtoneDB;Integrated Security=True;Asynchronous Processing=true"); 
    connection.Open(); 
    SqlCommand sqlCommand = new SqlCommand(); 
    sqlCommand.Connection = connection; 
    sqlCommand.CommandText = String.Format("IF NOT EXISTS(SELECT uniqueId FROM downloads WHERE uniqueID = '{0}') " + 
             "INSERT INTO downloads VALUES ('{0}', '{1}', '{2}') " + 
             "IF EXISTS(SELECT uniqueId FROM downloads WHERE uniqueID = '{0}') " + 
             "Update downloads " + 
             "set progress='{2}' " + 
             "where uniqueId='{0}' ", uniqueId, fileName, e.BytesReceived); 

    AsyncCallback callback = ((result) => 
    { 
     sqlCommand.EndExecuteNonQuery(result); 
     connection.Close(); 
    }); 

    sqlCommand.BeginExecuteNonQuery(callback, sqlCommand); 
} 

void wc_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e, string uniqueId, string fileName) 
{ 
    SqlConnection connection = new SqlConnection("Data Source=.\\SQLSERVER;Initial Catalog=XRingtoneDB;Integrated Security=True;Asynchronous Processing=true"); 
    connection.Open(); 
    SqlCommand sqlCommand = new SqlCommand(); 
    sqlCommand.Connection = connection; 

    sqlCommand.CommandText = String.Format("update downloads " + 
               "set progress='Completed' " + 
               "where uniqueId='{0}' and fileName='{1}'", uniqueId, fileName); 

    AsyncCallback callback = ((result) => 
    { 
     sqlCommand.EndExecuteNonQuery(result); 
     sqlCommand.Connection.Close(); 
    }); 
    sqlCommand.BeginExecuteNonQuery(callback, sqlCommand); 
} 

ProgressChanged工作正常但DownloadCompleted只能在調試模式下工作。 我認爲這是因爲我需要暫停或在這些調用之間等待。

Update3: 有時我在執行下載後有兩個相同的行在數據庫中! 困惑 我是否需要關閉所有連接?

回答

2

你應該調用BeginExecuteNonQuery的過載接受回調,並在回調結束查詢。

更新

如果您有需要對數據庫執行完成後執行額外的代碼,那麼這段代碼需要在回調中啓動。

例如,如果您目前有:

sqlCommand.BeginExecuteNonQuery(callback, sqlCommand); 
DoSomeAdditionalWorkNow(); 

DoSomeAdditionalWorkNow不會等到查詢完成,如果它取決於指令更新的數據,你就會有問題。

這可以通過調用額外的工作方法正在進入回調這樣補救:

AsyncCallback callback = ((result) => 
{ 
    sqlCommand.EndExecuteNonQuery(result); 
    connection.Close(); 
    DoSomeAdditionalWorkNow(); 
}); 
sqlCommand.BeginExecuteNonQuery(callback, sqlCommand); 

然而

我認爲你是過於複雜編程的生活。您正在執行的查詢是不長運行,您將與同步版本執行他們是完美的罰款:

sqlCommand.ExecuteNonQuery(); 
+0

我知道它。但是如何?請參閱更新中的問題。 – TheX

+0

@TheX:我已經用附加信息更新了答案。 –

+0

你看到我的更新嗎?我使用你的方法,但我的第二個查詢(當調用DonwloadCompleted())沒有運行。我想到了同步方法,但我不確定。如果1000個用戶一次調用查詢? – TheX

4

你可以使用的AsyncCallback代替Sleep()

AsyncCallback callback = new AsyncCallback(HandleCallback); 
sqlcommand.BeginExecuteNonQuery(callback, sqlcommand); 

處理使用回調的異步狀態。

private void HandleCallback(IAsyncResult result) 
{ 
    SqlCommand command = (SqlCommand)result.AsyncState; 
    command.EndExecuteNonQuery(result); 
    .... 
} 

更新2

代碼整體都不錯但是,你允許倍數文件下載一個唯一的ID?如果您正在下載具有相同唯一標識的不同文件它可能會更新報告不完整進度的下載表。

不確定你的意思DownloadCompleted只能在調試模式下工作,但是您可以在您的WebMethod中使用私有變量來控制流。說到這一點,由於您使用數據庫來更改報告狀態,但不會插入大量數據,因此您應該考慮使用同步查詢,以便更好地歸檔結果。

+0

我也嘗試過這種方法,但SQL查詢只運行一次。 PS。我的Sleep()方法會降低WebService和服務器的性能嗎? – TheX

+0

你是什麼意思的SQL查詢只運行一次。 是的,處理大量的數據,你不想等待(在你的情況下使用sleep()),直到處理完整個結果並處理它需要大量的RAM。 這只是一個更好的設計,只要它在Callback函數中可用,就可以利用異步模式處理數據。 – Turbot

+0

我的意思是,當我在Server Managament中查看我的數據庫時,只有第一次運行的是sql查詢。它不再更新。 – TheX