2011-12-06 23 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