У меня есть клиент-серверное приложение WCF, которое обменивается данными через HTTP с помощью WSHttpBinding.
Настройка сервера : самостоятельное размещение с использованием стандартного WCF ServiceHost
.
Мой фактический класс обслуживания приписывается как:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple,
InstanceContextMode = InstanceContextMode.PerSession,
UseSynchronizationContext = false)]
Настройка клиента : использование клиентского прокси-сервера, сгенерированного Visual-Studio, с использованием синхронных вызовов службы (proxy.call_server_method
блоков до тех пор, пока сервер не ответит полностью.)
Сценарий :
У меня есть один конкретный вызов метода, который занимает 20 секунд для выполнения на сервере. Клиент вызывает этот метод в отдельном потоке, поэтому он не задерживается, и ConcurrencyMode.Multiple
означает, что WCF также должен выполнить его в отдельном потоке на сервере.
Эта теория подтверждается тем фактом, что когда я настраиваю свое приложение для использования NetTcpBinding
, все работает нормально.
Проблема
Если я настраиваю приложение на использование WSHttpBinding
, то этот длинный вызов метода заставляет запросы http «резервировать». Я проверил это поведение как путем проверки моих журналов, так и путем отладки HTTP-запросов с использованием fiddler.
Пример:
- Клиент инициирует 20-секундный длинный запрос в фоновом потоке
- Клиент инициирует запрос B и C в основном потоке
- Запросы B и C отправляются на сервер, который не обрабатывает их, пока не выполнит 20-секундный длинный запрос
Но иногда:
- Запросы B и C не отправляются (они даже не появляются в fiddler), пока не вернется 20-секундный запрос (это редко).
- Примечание: установка
<add address="*" maxconnection="100"/>
в клиентском app.config привела к тому, что это (кажется) перестало происходить.
- Запрос B отправляется и получает ответ немедленно, в то время как запрос C задерживается до завершения 20-секундного (это редко)
Вот график от Fiddler, демонстрирующий проблему: (нажмите для увеличения)
Как видите, все запросы копируются на сервер. Как только 20-секундный запрос завершается, все ответы поступают, но обратите внимание, что есть некоторые запросы, которые не задерживаются ...
Итак, Вопросы :
- Какого черта здесь происходит? Почему он работает нормально с помощью
NetTcpBinding
и не работает с WSHttpBinding
?
- Почему противоречивое поведение?
- Что я могу сделать, чтобы это исправить?
Примечания:
- Он не блокируется на сервере. Я установил точки останова и использовал
!syncblk
, и он постоянно сообщает, что блокировки не удерживаются.
- Это не мои потоки (иначе NetTcpBinding не должен работать)
- У меня установлено
<serviceThrottling maxConcurrentCalls="1000" maxConcurrentInstances="1000" maxConcurrentSessions="1000" />
в app сервера .config
- 20-секундный вызов просто ожидает по таймеру, он не перегружает процессор, диск или сеть
- Я бы предпочел, чтобы решение, не включающее ре-архитектуру приложения, использовало асинхронные вызовы ... это большая куча устаревшего кода, и я действительно не хочу возиться с вещами, которые я не понимаю .