Как выполнить асинхронную транзакцию SQL в веб-сервисе ASP.NET - PullRequest
3 голосов
/ 06 декабря 2011

У меня есть веб-сервис со многими подключениями к нему. Я использовал этот код:

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

Я думаю, что это не лучший метод, потому что я называю Sleep(). PS. Этот метод будет замедлять производительность WebService и сервера

UPDATE2: я пытаюсь описать мой код больше: у меня есть WebClient и 2 события (ProgressChanged и DownloadCompleted)

[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 ]

4 голосов
/ 06 декабря 2011

вы можете использовать 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

в целом коды хороши, разрешено ли загружать несколько файлов в один уникальный идентификатор? Если вы загружаете разные файлы с одним и тем же уникальным идентификатором, это может обновить таблицу загрузок, которая сообщает о неполном прогрессе.

Не уверен, что вы имеете в виду DownloadCompleted работает только в режиме отладки, однако вы можете использовать личную переменную в вашем WebMethod для управления потоком. В связи с этим, поскольку вы используете БД для сообщения об изменении статуса, но не вставляете большой объем данных, вам следует рассмотреть возможность использования запросов синхронизации, чтобы можно было лучше заархивировать результат.

2 голосов
/ 06 декабря 2011

Вы должны вызвать перегрузку BeginExecuteNonQuery , которая принимает обратный вызов и в конце обратного вызова запрос.

Обновление

Если у вас естьдополнительный код, который необходимо выполнить после завершения выполнения базы данных, затем этот код необходимо запустить в обратном вызове.

Например, если у вас в данный момент есть:

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

DoSomeAdditionalWorkNow не будет ждать завершения запроса, и если это зависит от данных, обновленных в команде, у вас будут проблемы.

Это можно исправить, переместив вызов в дополнительный метод работы в обратный вызов как таковой:

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

Однако

Я думаю, чтоВы слишком усложняете свою жизнь программирования.Запросы, которые вы выполняете, не выполняются долго, и вы бы прекрасно выполняли их с синхронной версией:

sqlCommand.ExecuteNonQuery();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...