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

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

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

Соединение net.tcp работает на моей машине для разработки. Он также работает локально после развертывания на Windows Server 2008 R2. Тем не менее, он не работает удаленно, хотя можно удаленно подключиться к порту 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

привязки в IIS

Я также зашел в Расширенные настройки для веб-сайта и установил Включенные протоколы в http,net.tcp

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

введите описание изображения здесь

Подтверждение запуска веб-приложения

Сайт отлично работает для остальной части веб-приложения. Я настроил 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 ошибки Exchange: 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 в System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress) в системе.Net.Sockets.Socket.Connect(EndPoint remoteEP) в System.ServiceModel.Channels.SocketConnectionInitiator.Connect(Uri uri, TimeSpan timeout)

Если вы используете 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 открыт в брандмауэре? Да.
    • Брандмауэр отключен на сервере.
    • Я могу telnet к серверу на порт 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

Удачи

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

7 ответов

Решение

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

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

В своем вопросе вы упомянули, что вы подключились к "test.mydomain.com", но ошибка изменила сервер на "имя_компьютера". Затем в своем комментарии вы упомянули, что он все еще не может подключиться. Если вы хотите, чтобы псевдоним был возвращен в WSDL/MEX Добавьте узел useRequestHeadersForMetadataAddress в поведение службы. Вот информация MSDN об этом узле: 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>

Я предполагаю, что проблема, с которой вы столкнулись, заключается в том, что вам нужно настроить 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?

У вас есть служба общего доступа к портам Net.TCP, работающая на сервере, я полагаю... я не нашел ее прямо указанной.

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

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

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

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

<security mode="None"/>

привязка полного сервиса:

<netTcpBinding>

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

        <security mode="None"/>

    </binding>

</netTcpBinding>

Я надеюсь, что это может помочь вам тоже.

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

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

Другие вопросы по тегам