Размещение и закрытие одноразового подключения через ASP.NET WebService - PullRequest
0 голосов
/ 22 октября 2018

У нас есть служба поставщика, к которой мы обращаемся через соединение TCP / IP, но в любой момент времени у нас может быть только один активный логин.Поскольку эта служба доступна из нескольких приложений, мы настроили WebService (ASMX) и добавили Mutex для контроля доступа, поэтому одновременно выполняется только один вызов.

Однако служба должна подключиться, войтиin, введите команду и затем выходите каждый раз в текущем коде (ниже).

  using (var client = new Client(connectionSettings))
                    {
                        try
                        {
                            client.Login();
                            response.Response = client.SendCommand(command);
                            response.ErrorCode = WebserviceErrorCode.Success;
                            _lastSuccessfulConnection = DateTime.Now;
                        }
                        catch (IOException oex)
                        {
                            response.ErrorMessage = oex.Message;
                            response.ErrorCode = WebserviceErrorCode.UnabletoConnect;
                            return response;
                        }
                        catch (System.Net.Sockets.SocketException socEx)
                        {
                            response.ErrorMessage = socEx.Message;
                            response.ErrorCode = WebserviceErrorCode.SocketException;
                            return response;
                        }

                        client.Logout();
                    }

Это очевидно неэффективно, если несколько клиентов делают запросы - мы бы предпочли держать соединение открытым, скажем, 10 секунди затем закройте его, если больше не будет никаких команд.

Я пытаюсь найти лучший способ сделать это безопасно в ASP.NET.Должны ли мы использовать Hangfire, QueueBackgroundWorkItem?

1 Ответ

0 голосов
/ 05 ноября 2018

После некоторых исследований я решил использовать QueueBackgroundWorkItem

. Это запланирует фоновую задачу, которая не зависит от потока запроса, и, следовательно, будет продолжать выполняться после завершения запроса.

Примечание: Это не постоянная система очередей (она не будет хранить их, например, при перезапуске веб-процесса), но поскольку это просто закрытие соединенияэто нормально для этого сценария.

Реализация

Когда к моему сервису делается запрос, он использует класс static для получения одного клиента (доступ контролируется с помощью Mutex) и введите команду.Затем он вызывает эту процедуру:

private static void CreateTimeoutCheck()
{
      Action<CancellationToken> workItem = TimeoutConnection;
      System.Web.Hosting.HostingEnvironment.QueueBackgroundWorkItem(workItem);
      Log.Information("A timeout check has been created");
}

Это вызовет этот метод в фоновом режиме:

 /// <summary>
 /// Job that runs in background, waits 10 seconds then attempts to close the client
 /// </summary>
 /// <param name="cancellationToken"></param>
 private static async void TimeoutConnection(CancellationToken cancellationToken)
 {
     Log.Information("Timeout check waiting...");
     await Task.Delay(timeoutMS);
     Log.Information("Timeout check being made");
     CheckForTimeout();
 }

Единственное, что меня беспокоит в этом подходе, это то, что я порождаю одинрабочий элемент в пуле потоков на запрос, и если служба интенсивно используется, это может вызвать проблему.Однако каждый из них просто выполняет асинхронное ожидание, поэтому я надеюсь, что это не вызовет проблемы.Служба используется внутренне, поэтому мы контролируем количество / частоту запросов к ней - я бы больше волновался, если бы это было обнаружено извне.

Метод CheckForTimeout довольно прост:

/// <summary>
/// Check to see if we have had more recent commands
/// </summary>
private static void CheckForTimeout()
{
    var secsSinceLastCmd = DateTime.Now.Subtract(_lastCommand).TotalSeconds;
    if (secsSinceLastCmd >= clientTimeoutSecs)
    {
        // logout and close client
        Log.Information($"Client timeout: {secsSinceLastCmd:0.0} sec since last command");
        CloseClient();
    }
}

Я собираюсь некоторое время следить за обновленным сервисом, чтобы убедиться, что он работает нормально, но пока тесты показывают, что он работает как положено.

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