Я пишу приложение Datasnap с TCP-соединением между клиентом и сервером, с сервером, подключенным к SQL-серверу.
Сервер имеет модуль данных DM1 со всеми запросами к набору данных и соединением SQL. DM1 также имеет компоненты REST-запрос / клиент / ответ.
DM1 имеет открытую функцию PostDataAsync с идентификатором param: для генерации json из набора данных, а затем HTTP отправляет его в службу RESTFul. Возвращает количество записей, которые не удалось опубликовать в аргументе обратного вызова.
DSServer этого DM1 - «Invocation».
Тип сервера вызова должен обеспечивать, чтобы каждый вызов метода сервера имел свое собственное соединение с БД, набор данных, компоненты Rest, которые не будут иметь множественные вызовы, мешающие данным друг друга (если добавлена параллельная многопоточность).
procedure TServerMethods1.postCustOrderHistAsync(CustomerID: String; callback: TDBXcallback);
var
jsonObject: TJSONObject;
CallbackValue: TJsonValue;
errors: Integer;
begin
errors := postCustOrderHist(CustomerID); //takes time to post, returns num of failed records
jsonObject := TJSONObject.create;
jsonObject.AddPair(tjsonpair.create('errors', errors.ToString));
CallbackValue := callback.Execute(jsonObject);
end;
Клиент имеет кнопку, которая вызывает метод сервера PostDataAsync с ID param, а также функцию обратного вызова «ShowNotification» (которая использует центр уведомлений Windows для отображения статуса уведомления Post).
На данный момент приложение работает следующим образом: клиент вызывает функцию сервера синхронно, это означает, что основной поток ожидает, пока функция сервера завершит HTTP-публикацию, а затем запускает уведомление об обратном вызове; клиент тем временем висит.
TDSCallbackWithMethod = class(TDBXCallback)
private
FCallbackMethod: TDSCallbackMethod;
public
constructor Create(ACallbackMethod: TDSCallbackMethod);
function Execute(const Args: TJSONValue): TJSONValue; override; //executes FCallbackMethod
end;
procedure TMainForm.BtnPostOrderHistoryClick(Sender: TObject);
var
callback: TDBXCallback;
ServerMethods1Client: TServerMethods1Client;
begin
//Define Callback to show notification
callback := TDSCallbackWithMethod.Create(
function(const Args: TJSONValue): TJSONValue
var
errors: integer;
begin
errors := Args.GetValue<integer>('errors');
if errors = 0 then
showNotification(StrSentSuccessfully)
else
showNotification(StrSendingFailed + '(' + errors.ToString + ' not sent)');
result := TJsonTrue.Create;
end);
//Call Server Method
ServerMethods1Client := TServerMethods1Client.Create(DMServerConnection.SQLConnection1.DBXConnection);
try
ServerMethods1Client.postCustOrderHistAsync(EditCustomerId.Text, callback)
finally
ServerMethods1Client.Free;
end;
end;
Каким должен быть проект, чтобы асинхронно вызывать методы сервера и позволить серверу выполнить обратный вызов по завершении? Функция Post должна вызываться несколько раз одним и тем же пользователем или несколькими пользователями одновременно.
Должен ли поток быть на стороне сервера или на стороне клиента? Если кто-то может помочь с этим, я могу отправить демонстрационную версию приложения, используя базу данных Northwind.
Примечание: я попытался запустить вызов клиентской функции в TTask, он работает, когда пользователь запускает функцию по одному за раз. Но когда серверный метод запускается одновременно несколько раз, я получаю «DBXError… Ошибка чтения… обратный вызов, ожидающий X получил Y». Кажется, что пока клиент ожидает формат ответного обратного вызова из первого запроса, он путается с другими пакетами протокола tcp, инициированными из второго запроса. Я попытался запустить ttask на стороне сервера, я получил исключение "TOLEDBCommand.Destroy - интерфейсы не выпущены"