Настройка службы WCF TCP в веб-приложении

Я боролся с этим в течение нескольких дней, буквально просматривая сто статей, дающих частичные рекомендации о том, как настроить службу WCF на основе TCP в веб-приложении. Если кто-то может мне помочь, я сделаю этот вопрос в полный.

Текущее состояние

Соединение net.tcp работает на моей машине разработки. Он также работает локально после развертывания на Windows Server 2008 R2. Тем не менее, он не работает удаленно, даже несмотря на то, что удаленно можно отправить telnet на порт 808 на сервере. Чтобы узнать подробности, прокрутите страницу до конца. Пожалуйста, помогите, если сможете.

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

код

Я создал ServerHubService.svc со следующим содержимым:

namespace Manage.SignalR
{
    [ServiceContract]
    public class ServerHubService
    {
        [OperationContract]
        public void UpdateServerStatus(string serverStatus)
        {
            // Do something
        }
    }
}

Конфигурация приложения, на котором размещена служба

Следуя интерактивному учебнику, я добавил следующее к моему Web.config(я пробовал МНОГИЕ разные варианты). Это Web.config веб-приложения, на котором размещена служба, с которой я позже хочу подключиться к TCP.

<configuration>
  <system.serviceModel>
    <services>
      <service behaviorConfiguration="ServerHubBehavior"
      name="Manage.SignalR.ServerHubService">
        <endpoint address=""
              binding="netTcpBinding"
              bindingConfiguration="portSharingBinding"
              name="MyServiceEndpoint"
              contract="Manage.SignalR.ServerHubService">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>

        <endpoint address="mex"
              binding="mexTcpBinding"
              bindingConfiguration=""
              name="MyServiceMexTcpBidingEndpoint"
              contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://test.mydomain.com:808/SignalR/ServerHubService.svc" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ServerHubBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <netTcpBinding>
        <binding name="portSharingBinding" portSharingEnabled="true"/>
      </netTcpBinding>
    </bindings>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
      minFreeMemoryPercentageToActivateService="0" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
</configuration>

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

Конфигурация сервера, на котором работает веб-приложение

Я настраиваю это на моей машине разработки, которая имеет IIS 7.5

Я читал, что IIS Express (встроенный в Visual Studio) не поддерживает net.tcp, поэтому я создал новый веб-сайт в IIS 7.5 с использованием .NET 4.5 и имеет привязку net.tcp

bindings in IIS

Я также перешел в "Дополнительные настройки" для веб-сайта и установил Enabled Protocols на http,net.tcp

Я удостоверился, что активирована функция активации HTTP без активации HTTP (и перезапущена). Это функция Windows, поэтому найдите "Включить или отключить функции Windows", чтобы найти это.

enter image description here

Подтверждение веб-приложения выполняется

Веб-сайт отлично работает для остальной части веб-приложения. Я установил test.mydomain.com, чтобы указать 127.0.0.1 в моем файле hosts. Я даже могу посетить http://test.mydomain.com/SignalR/ServerHubService.svc, и он покажет мне хорошую автоматически созданную страницу из .NET, объяснив, как использовать эту службу.

Пока все хорошо.

Страница, сгенерированная .NET, позволяет мне использовать этот адрес для создания подключения к моей службе:

net.tcp://computername/SignalR/ServerHubService.svc/mex

Попытка подключения к службе как клиента

Если вы не запомните установку httpGetEnabled="true", вы получите сообщение об ошибке при попытке создать ссылку на службу. Если вы используете тестовый клиент WCF (также инструмент, включенный в Visual Studio) и не установили httpGetEnabled, вы получите сообщение об ошибке, как показано ниже:

Ошибка: невозможно получить метаданные из net.tcp://computername/SignalR/ServerHubService.svc/mex

Если это служба Windows (R) Communication Foundation, к которой вы получите доступ, убедитесь, что вы включили публикацию метаданных в указанный адрес. Чтобы помочь в публикации метаданных, пожалуйста, обратитесь к документации MSDN по адресу http://go.microsoft.com/fwlink/?LinkId=65455.WS-Metadata

URI ошибки обмена: net.tcp://computername/SignalR/ServerHubService.svc/mex Метаданные содержит ссылку, которая не может быть решена: 'Net.tcp://computername/SignalR/ServerHubService.svc/mex. Не мог подключитесь к net.tcp://computername/SignalR/ServerHubService.svc/mex. Попытка подключения продолжалась в течение промежутка времени 00: 00: 04.0032289.

Код ошибки TCP 10061: соединение не может быть выполнено, поскольку цель машина активно отказалась [2001: 0: 4137: 9e76: c81: a4c: a547: b2fd]: 808. Соединение не может быть выполнено, поскольку активная целевая машина отказался [2001: 0: 4137: 9e76: c81: a4c: a547: b2fd]: 808

Однако, если вы сделали все, как указано выше, вы должны иметь возможность добавить ссылку на службу.

Методы вызова в службе

При попытке вызвать простой метод Hello World в службе из тестового клиента WCF, он возвращает следующую ошибку:

Не удалось подключиться к net.tcp://computername/SignalR/ServerHubService.svc. Связь попытка длилась в течение 00: 00: 04.0002288. Код ошибки TCP 10061: соединение не может быть выполнено, поскольку активная целевая машина отказался.

Это внутренний стек, который включен с ошибкой:

Никакое соединение не может быть выполнено, поскольку активная целевая машина отказался [2001: 0: 5ef5: 79fb: 3884: a: a547: b2fd]: 808 at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress) в System.Net.Sockets.Socket.Connect(EndPoint remoteEP) в System.ServiceModel.Channels.SocketConnectionInitiator.Connect(Uri uri, тайм-аут TimeSpan)

Если вы используете netstat -an |find /i "listening", чтобы увидеть, что ничто не слушает порт 808, вероятно, потому, что служба адаптера прослушивателя Net.Tcp не запущена.

Подтверждение

Теперь вызов проходит, но требуется подтверждение, прежде чем его можно будет объявить успешным. Мне нужно подтвердить, что на самом деле это net.tcp вызывает порт 808, а не вызов на конечную точку http. Я пытаюсь сделать это с Wireshark, но он не отображается, вероятно, потому, что это вызов происходит с моей локальной машины.

Развертывание

Последней задачей завоевания было бы развернуть это на веб-сервере, гарантируя, что то, что работает на машине разработки, также работает на веб-сервере.

Он не работает после публикации в Windows Server 2008 R2. Он дает общий SocketException: An existing connection was forcibly closed by the remote host.

Он хорошо работает локально на сервере, но он не работает удаленно.

Вот контрольный список, используемый для проверки сервера:

  • Работает ли служба Net.Tcp Listener Adapter? Да
  • Является ли привязка сайта IIS к net.tcp к 808:*? Да
  • Включены ли протоколы с расширенными настройками для сайта в IIS, установленном на http,net.tcp? Да
  • Служит ли сервер на порту 808? Да, с помощью netstat -an |find /i "listening"
  • Открыт ли порт 808 в брандмауэре? Да.
    • Брандмауэр отключен на сервере.
    • Я могу подключиться к серверу на порту 808 извне с помощью telnet mydomain.com 808
  • В конфигурации службы на сервере было подтверждено следующее:
    • baseAddress настроен на net.tcp://mydomain.com:808/SignalR/ServerHubService.svc
    • Это было localhost раньше, но сменилось на mydomain.com после того, как оно не работало на сервере: <identity><dns value="mydomain.com" /></identity>
  • Он был протестирован с клиентом локально на сервере и на другом сервере. Оба могут подключаться к порту 808 с помощью telnet, и оба дают одинаковое сообщение об ошибке.

Какая конфигурация может отсутствовать на сервере? Я так близок к цели. Пожалуйста, помогите мне в устранении неполадок и заполните вопрос.

Вот клиентская конфигурация на сервере, вызывающая службу:

<system.serviceModel>
  <bindings>
    <netTcpBinding>
      <binding name="MyServiceEndpoint" />
    </netTcpBinding>
  </bindings>
  <client>
    <endpoint address="net.tcp://mydomain.com:808/SignalR/ServerHubService.svc"
      binding="netTcpBinding" bindingConfiguration="MyServiceEndpoint"
      contract="ServerHubService.ServerHubService" name="MyServiceEndpoint">
      <identity>
        <dns value="mydomain.com" />
      </identity>
    </endpoint>
  </client>
</system.serviceModel>

Я также пробовал без 808, сконфигурированных в конечной точке, так как это, по слухам, является портом по умолчанию для соединений net.tcp. Однако он все равно дает тот же результат.

Вместо того, чтобы делать много вещей случайным образом, может быть, хороший вопрос: как отлаживать что-то подобное? Могу ли я установить программу на любом сервере, которая точно скажет мне, почему этот вызов блокируется?

Когда Wireshark настроен таким образом, можно посмотреть вызов, поступающий на сервер на порт 808, и, возможно, определить, почему вызов не работает. Однако я понятия не имею, как анализировать это в настоящее время.

wireshark

Удача

Я отказался и реализовал это в слое сокета. Он работал немедленно. Надеюсь, это может помочь кому-то еще. Я устанавливаю ответ, потому что многие из проблем были решены, и он действительно работал локально в конце концов, поэтому любая оставшаяся проблема, вероятно, связана со мной конкретной средой.

Ответ 1

Вам необходимо создать прокси-сервер, основанный на метаданных, выставленных через HTTP для tcp (убедитесь, что для параметра httpGetEnabled установлено значение true). Адрес, который вы используете на клиенте, должен быть размещенным адресом. Пожалуйста, напишите ниже.

http://blogs.msdn.com/b/swiss_dpe_team/archive/2008/02/08/iis-7-support-for-non-http-protocols.aspx

Ответ 2

В вашем вопросе вы упомянули, что вы подключились к "test.mydomain.com", но ошибка изменила сервер на "имя_компьютера". Тогда в своем комментарии вы упомянули, что он все еще не подключается. Если вы хотите, чтобы псевдоним, возвращаемый в WSDL/MEX, добавляет useRequestHeadersForMetadataAddress node в ваше поведение службы. Вот информация MSDN об этом node: MSDN useRequestHeadersForMetadataAddress node

Вот как выглядит ваш конфиг. Это учитывает ответ, заданный Prasath (httpGetEnabled = "true" ).

<serviceBehaviors>
   <behavior name="ServerHubBehavior">
      <serviceMetadata httpGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="false" />
      <useRequestHeadersForMetadataAddress>
         <defaultPorts>
            <add scheme="net.tcp" port="808" />
         </defaultPorts>
      </useRequestHeadersForMetadataAddress>
   </behavior>
</serviceBehaviors>

Ответ 3

Хостинг службы на основе TCP в IIS всегда был медведем. WCF позволяет легко запускать собственный хост службы, прослушивая ваш TCP-порт. Моей рекомендацией было бы сделать это и настроить его для работы в качестве службы Windows.

Смотрите эту статью: http://msdn.microsoft.com/en-us/library/ff649818.aspx

Ответ 4

Я предполагаю, что проблема заключается в том, что вам нужно настроить SPN (имя участника службы) для вашей службы WCF (на компьютере) и добавить его в учетную запись службы, под которой работает служба.

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

Я знаю, что это беспокоит, и, как правило, это сюрприз, ожидающий нас, когда наш сервис готов к развертыванию в производственных или предварительных производственных средах.

SPN используется Kerberos во время процесса аутентификации.

Попробуйте использовать IP-адрес машины для разрешения вашей службы вместо имени хоста. (Это не должно требовать SPN), замените "test.mydomain.com" на IP-адрес устройства:

<host>
    <baseAddresses>
        <add baseAddress="net.tcp://192.168.0.253:808/SignalR/ServerHubService.svc" />
    </baseAddresses>
</host>

Взгляните на эти статьи: - Kerberos для Занятого Администратора
- WCF в интранете с проверкой подлинности Windows
- Для следующего сообщения попробуйте прочитать тот, который не принят в качестве ответа: Какой SPN мне нужно установить для службы net.tcp?

Ответ 5

Вы пытались запустить службу (для целей тестирования) в службе Windows на вашем локальном компьютере? Таким образом, вы, по крайней мере, узнаете, есть ли проблема на стороне службы или на настройке IIS/сервера.

Ответ 7

У меня была аналогичная проблема сегодня, когда вы вызываете службу wcf net.tcp изнутри app.net asp.net. Я не буду говорить, что со всех других машин эта служба работала годами, но звонки были сделаны wcf самостоятельно, wcf iis asp.net совместимость хостинга → против сервиса net.tcp самостоятельно. Когда я опубликовал свой простой веб-апи, вызывающий тот же сервис net.tcp, все пошло не так, и все соединения были прерваны без какой-либо причины, даже полная трассировка wcf с обеих сторон (служба и клиент) не помогла, просто сообщив то же самое msgstr "соединение прервано".

Я уже знал, что net.tcp поставляется с защитой от транспорта, с использованием проверки подлинности Windows для подписывания и шифрования связи, поэтому я просто попытался отключить систему безопасности, и все начинает работать должным образом.

Просто попробуйте отключить защиту таким образом обе стороны (клиент и сервис):

<security mode="None"/>

привязка полной службы:

<netTcpBinding>

    <binding name="netTcpBinding" portSharingEnabled="true">

        <security mode="None"/>

    </binding>

</netTcpBinding>

Надеюсь, это тоже поможет.