Конфиги WCF-сервисов, обеспечивающие совместимость с JAVA, PHP, FLEX.
Сделать что-либо сложно - ума большого не надо. Мозги нужны чтобы сделать что-нибудь просто. В теме WCF все придумано чрезмерно сложно. Скажем стандартно клиент должен идентифицировать себя с помощью клиентского сертификата. Как-бы это кажется просто - и у меня действительно много сервисов, работающих именно так - вот тут пример установки такого сертификата для шлюза Инплата - Организация SSL транспортного уровня по программно загружаемому клиентскому сертификату. Фишка однако в том, что даже это несложное действие часто слишком сложно и требует высокой квалификации программистов и админов. Ну сделал это один раз человек с ЗП 150 тысяч в месяц, а через полгода сертификат прокис и (вдруг) в выходной день перед длительными праздниками перестали проходить платежи. Тот кто это когда-то сделал - уже давно где-нибудь в штатах. Дернулись на фриланс, дали удаленный доступ (вроде бы) специалисту - он немного поковырялся в реестре и все, конец. Теперь и тот специалист с доходом 150-200 тысяч в месяц уже никогда не восстановит жизнедеятельность фирмы. Не встречались пока с такой ситацией?
Поэтому делать надо просто, предельно просто, насколько возможно просто. Конечно, когда касается прохождения платежей - простота вредит - я об этом писал много раз (Шлюзы к платежным системам интернет-денег, Безопасность Web-приложений ) - во всех остальных случаях надо жертвовать безопасностью ради простоты.
WCF - предельно накрученая в плане сложности технология. Давайте скажем для начала, что основной кнфигурационный файл WCF-сервиса содержит 128 основных рабочих блоков (тегов первого уровня) - от ActionNotSupportedException до XPathMessageQuery и 37 основных пераметров-перечислений. Каждый из 128 блоков управления WCF верхнего уровня содержит десятки или сотни управляющих параметровю Ну например у WSHttpBinding (тег управления WCF верхнего уровня) имеется 22 основных рабочих режима, которые может установить администратор в конфиге и плюс 30 методов, которыми может пользоватся программист в коде. У ServiceHost - 17 основных свойств (режимов работы) и 55 методов работы для программиста. Примерно так же во всех остальных 128-ми блоках управления WCF. В каких-то сочетаниях это работает так, а в каких-то иначе. Понятно, что такие обьемы параметров, управляющих алгоритмами библиотеки WCF - System.ServiceModel.dll и System.ServiceModel.Web.dll никому в пользу не пойдут. Изучить сложное взаимодействие управляющих параметров и их влияние на алгоритмы в этих DLL - гораздо сложнее, чем написать с нуля самому эти же алгоритмы для свой собственной задачки. В общем, надо признать - индусы круто научились тащить из Билла-Дебила деньги.
В ряде случаев помоечный индустский код так и не удается настроить на совместимость например с Явой (несмотря на титанические усилия и массу убитого времени). Я об этом писал тоже уже много раз. И сделал свой собственный клиент WCF вместо всех этих индустских помоев - WCF_CLIENT - клиент Web-сервиса.
Для этого конечно надо понимать основные алгоритмы WCF. На мой взгляд делать web-сервисы исключительно для взаимодействия NET-NET или только для локалки - это маразм. Поэтому на самом верхнем уровне контроля алгоритмов WCF есть смысл выбирать только базовую или WS - привязки. Ну или MSMQ в тех редких случаях когда требуется отсоединенное отложенное взаиможействие между клиентом и сервисом. Кроме того, конечно нужна MEX-привязка (metadata exchange) - без нее WCF вырождается в полный маразм и превращается в простой обмен XML - я писал об этом тоже много раз - SOAP/WSDL vs XML data exchange. А в целом в WCF поддерживается 20 типов привязок.
- basicHttpBinding
- basicHttpContextBinding
- mexHttpBinding
- mexHttpsBinding
- mexNamedPipeBinding
- mexTcpBinding
- msmqIntegrationBinding
- netMsmqBinding
- netNamedPipeBinding
- netPeerTcpBinding
- netTcpBinding
- netTcpContextBinding
- webHttpBinding
- wsDualHttpBinding
- wsFederationHttpBinding
- wsHttpBinding
- wsHttpContextBinding
- ws2007FederationHttpBinding
- ws2007HttpBinding
- customBinding
У каждой привязки свои способы кодирования, свои способы обеспечения надежной или ненадежной доставки сообщений строго по очереди или произвольно, свои способы поддержки транзаккций (что-то поддерживается иногда, а что-то нет), свои возможные режимы работы сервиса - PerCall, Session, Singlton. Ну и миллион различных режимов (и их сочетаний) в плане безопасности - где-то что-то можно шифровать только на транспортном уровне, где-то возможен логин/пароль, в каких-то случаях клиентский сертификат, в каких-то электронный токен, в каких-то ацтентифкация кампутера. Обратные вызовы в каких-то случаях возможны, в каких-то нет, куки и совместимость с ASP.NET в каких-то сочетаниях параметров возможны, в каких-то нет.
Поэтому первой задачкой для любого программиста - как из всех этих индустских помоев - сделать себе рабочие конфигурации для тех или иных обычных случаев. Ну и при наличии необходимости усиления безопасности - начинать с этих контрольных точек двигатся дальше.
Итак, простейший конфиг для базовой привязки, совместимый с JAVA, FLEX и другими средами вы видите ниже. Это железно работающий минимальный конфиг WCF - разумеется вам надо вписать свои адреса сервисов и свои классы.
1: <?xml version="1.0" encoding="UTF-8"?>
2: <configuration>
3: <system.web>
4: <authentication mode="None" />
5: <customErrors mode="Off"/>
6: <compilation debug="true" strict="false" explicit="true" targetFramework="4.0" />
7: </system.web>
8: <system.serviceModel>
9: <standardEndpoints />
10: <services>
11: <service behaviorConfiguration="Behavior0" name="FlyService.TicketList">
12: <endpoint address="http://flyservice.vb-net.com/TicketList.svc"
13: binding="basicHttpBinding" bindingConfiguration="basicHttpBinding0"
14: contract="FlyService.ITicketList" />
15: </service>
16: <service behaviorConfiguration="Behavior0" name="FlyService.CursUSD">
17: <endpoint address="http://flyservice.vb-net.com/CursUSD.svc"
18: binding="basicHttpBinding" bindingConfiguration="basicHttpBinding0"
19: contract="FlyService.ICursUSD" />
20: </service>
21: <service behaviorConfiguration="Behavior0" name="FlyService.CityCountry">
22: <endpoint address="http://flyservice.vb-net.com/CityCountry.svc"
23: binding="basicHttpBinding" bindingConfiguration="basicHttpBinding0"
24: contract="FlyService.ICityCountry" />
25: </service>
26: </services>
27: <bindings>
28: <basicHttpBinding>
29: <binding name="basicHttpBinding0" />
30: </basicHttpBinding>
31: </bindings>
32: <behaviors>
33: <serviceBehaviors>
34: <behavior name="Behavior0">
35: <serviceMetadata httpGetEnabled="true" />
36: <serviceDebug includeExceptionDetailInFaults="false" />
37: </behavior>
38: </serviceBehaviors>
39: </behaviors>
40: <serviceHostingEnvironment multipleSiteBindingsEnabled="false" aspNetCompatibilityEnabled="false" >
41: </serviceHostingEnvironment>
42: </system.serviceModel>
43: <system.webServer>
44: <modules runAllManagedModulesForAllRequests="true" />
45: <defaultDocument>
46: <files>
47: <add value="Default.aspx" />
48: </files>
49: </defaultDocument>
50: </system.webServer>
51: </configuration>
Ту же самую конфигурацию можно немного расширить, потому что длины сообщений, таймаутов и прочего часто не хватает. Конфигурацию клиента можно создать самой студией, поставив ссылку на свой собственный сервис. Тогда получается вот такая (слегка расширенная конфигурация:
1: <?xml version="1.0" encoding="UTF-8"?>
2: <configuration>
3: <system.web>
4: <authentication mode="None" />
5: <customErrors mode="Off"/>
6: <compilation debug="true" strict="false" explicit="true" targetFramework="4.0" />
7: </system.web>
8: <system.serviceModel>
9: <client>
10: <endpoint address="http://flyservice.vb-net.com/CursUSD.svc"
11: binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding0"
12: contract="FlyService.ICursUSD" name="ClientEndpoin_CursUSD" />
13: <endpoint address="http://flyservice.vb-net.com/TicketList.svc"
14: binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding0"
15: contract="FlyService.ITicketList" name="ClientEndpoint_TicketList0" />
16: <endpoint address="http://flyservice.vb-net.com/CityCountry.svc"
17: binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding0"
18: contract="FlyService.ICityCountry" name="ClientEndpoint_CityCountry0" />
19: </client>
20: <standardEndpoints />
21: <services>
22: <service behaviorConfiguration="Behavior0" name="FlyService.TicketList">
23: <endpoint address="http://flyservice.vb-net.com/TicketList.svc"
24: behaviorConfiguration="" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding0"
25: contract="FlyService.ITicketList" />
26: </service>
27: <service behaviorConfiguration="Behavior0" name="FlyService.CursUSD">
28: <endpoint address="http://flyservice.vb-net.com/CursUSD.svc"
29: behaviorConfiguration="" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding0"
30: contract="FlyService.ICursUSD" />
31: </service>
32: <service behaviorConfiguration="Behavior0" name="FlyService.CityCountry">
33: <endpoint address="http://flyservice.vb-net.com/CityCountry.svc"
34: behaviorConfiguration="" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding0"
35: contract="FlyService.ICityCountry" />
36: </service>
37: </services>
38: <bindings>
39: <basicHttpBinding>
40: <binding name="BasicHttpBinding0" closeTimeout="00:01:00"
41: openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
42: allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
43: maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
44: messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
45: useDefaultWebProxy="true">
46: <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
47: maxBytesPerRead="4096" maxNameTableCharCount="16384" />
48: <security mode="None">
49: <transport clientCredentialType="None" proxyCredentialType="None"
50: realm="" />
51: <message clientCredentialType="UserName" algorithmSuite="Default" />
52: </security>
53: </binding>
54: </basicHttpBinding>
55: </bindings>
56: <behaviors>
57: <serviceBehaviors>
58: <behavior name="Behavior0">
59: <serviceMetadata httpGetEnabled="true" />
60: <serviceDebug includeExceptionDetailInFaults="false" />
61: </behavior>
62: </serviceBehaviors>
63: </behaviors>
64: <serviceHostingEnvironment multipleSiteBindingsEnabled="false" aspNetCompatibilityEnabled="false" >
65: </serviceHostingEnvironment>
66: </system.serviceModel>
67: <system.webServer>
68: <modules runAllManagedModulesForAllRequests="true" />
69: </system.webServer>
70: </configuration>
Как и первая конфигурация - эта конфигурация железно работает с любыми клиентами - PHP, FLEX, JAVA и проч. Ниже вы видите как этот сервис читается клиентом JAVA:
Однако, это самый убогий вариант WCF. В нем даже не обеспечивается поддержка последовательности вызовов службы из клиента. То есть более поздний пакет с вызовом из клиента службы может прийти раньше. На практике я сталкивался с этим сто раз. Например в базу пишется первой записью сначала ключ, а в следущем обращении некие данные, ссылающиеся на этот ключ. В итоге софт ИНОГДА падает. В тех случаях когда ключ попадает в базу позже чем данные, ссылающиеся на него. Ну а если софт делал крутой (программист - укрыватель исключений) - ИНОГДА некоторые записи будут пропадать. Ну типа - иногда все 1000 заказов попали в базу точно, а иногда 999, а иногда 990.
Это лишь один аспект работы WCF - а их (как мы видели выше) - 180 основных крупных блоков. Один из блоков - безопасность. Там тысячи режимов. Ну для примера в базовой привязке не поддерживается аутентификация по имени пользователя и пароля, а в привязке WS - она уже поддерживается. Ну и в этом конфиге никакая защита не обеспечивается - все передается открытым текстом. Зато базовая привязка совместима с ASMX-клиентами, а WS - только с клиентами следующих поколений.
1: <?xml version="1.0" encoding="UTF-8"?>
2: <configuration>
3: <system.web>
4: <authentication mode="None" />
5: <customErrors mode="Off"/>
6: <compilation debug="true" strict="false" explicit="true" targetFramework="4.0" />
7: </system.web>
8: <system.serviceModel>
9: <client>
10: <endpoint address="http://flyservice.vb-net.com/CursUSD.svc"
11: binding="wsHttpBinding" bindingConfiguration="wsHttpBinding0"
12: contract="FlyService.ICursUSD" name="ClientEndpoin_CursUSD" />
13: <endpoint address="http://flyservice.vb-net.com/TicketList.svc"
14: binding="wsHttpBinding" bindingConfiguration="wsHttpBinding0"
15: contract="FlyService.ITicketList" name="ClientEndpoint_TicketList0" />
16: <endpoint address="http://flyservice.vb-net.com/CityCountry.svc"
17: binding="wsHttpBinding" bindingConfiguration="wsHttpBinding0"
18: contract="FlyService.ICityCountry" name="ClientEndpoint_CityCountry0" />
19: </client>
20: <standardEndpoints />
21: <services>
22: <service behaviorConfiguration="Behavior0" name="FlyService.TicketList">
23: <endpoint address="http://flyservice.vb-net.com/TicketList.svc"
24: behaviorConfiguration="" binding="wsHttpBinding" bindingConfiguration="wsHttpBinding0"
25: contract="FlyService.ITicketList" />
26: </service>
27: <service behaviorConfiguration="Behavior0" name="FlyService.CursUSD">
28: <endpoint address="http://flyservice.vb-net.com/CursUSD.svc"
29: behaviorConfiguration="" binding="wsHttpBinding" bindingConfiguration="wsHttpBinding0"
30: contract="FlyService.ICursUSD" />
31: </service>
32: <service behaviorConfiguration="Behavior0" name="FlyService.CityCountry">
33: <endpoint address="http://flyservice.vb-net.com/CityCountry.svc"
34: behaviorConfiguration="" binding="wsHttpBinding" bindingConfiguration="wsHttpBinding0"
35: contract="FlyService.ICityCountry" />
36: </service>
37: </services>
38: <bindings>
39: <wsHttpBinding>
40: <binding name="wsHttpBinding0" closeTimeout="00:01:00" openTimeout="00:01:00"
41: receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false"
42: transactionFlow="false" hostNameComparisonMode="StrongWildcard"
43: maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text"
44: textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
45: <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
46: maxBytesPerRead="4096" maxNameTableCharCount="16384" />
47: <reliableSession ordered="true" inactivityTimeout="00:10:00"
48: enabled="false" />
49: <security mode="None">
50: <transport clientCredentialType="None" proxyCredentialType="None"
51: realm="" />
52: <message clientCredentialType="None" negotiateServiceCredential="false"
53: establishSecurityContext="false" />
54: </security>
55: </binding>
56: </wsHttpBinding>
57: </bindings>
58: <behaviors>
59: <serviceBehaviors>
60: <behavior name="Behavior0">
61: <serviceMetadata httpGetEnabled="true" />
62: <serviceDebug includeExceptionDetailInFaults="false" />
63: </behavior>
64: </serviceBehaviors>
65: </behaviors>
66: <serviceHostingEnvironment multipleSiteBindingsEnabled="false" aspNetCompatibilityEnabled="false" >
67: </serviceHostingEnvironment>
68: </system.serviceModel>
69: <system.webServer>
70: <modules runAllManagedModulesForAllRequests="true" />
71: </system.webServer>
72: </configuration>
Увы, такая конфигурация (кажущаяся вполне разумной) - изумительно работает только с NET-клиентами. С NET-клиентами, ее можно расширять и гнуть в любую сторону. Однако стоит выйти за рамки NET - и начинаются проблемы. Альтова почему-то начинает пихать в POST-реквесты какие-то неадекватные заголовки - а Альтова в приницпе считается эталонным кроссплатформенным клиентом (понятно что микрософтовским клиентом нет никакого смысла даже тестировать WCF - все будет работать).
Ниже вы видите удачный протокол работы Altova с WCF-сервисом, сконфигурированным basicHttpBinding:
А вот здесь я изменил привязку с basicHttpBinding на wsHttpBinding - и тестовый кроссплатформенный клиент сразу же зглючило:
Хотя WSDL по прежнему читается тестовым клиентом XMLSPY:
Единственная среда - которой сложно прочитать даже WSDL при wsHttpBinding - JAVA. И действительно WSDL меняется при изменении привязки радикально. При базовой привязки (простейший сервис) - который выдает одно десятичное число при обращении к нему (курс валюты, по которому работает конкретная фирма) - WSDL выглядит вот так:
1: <wsdl:definitions name="CursUSD" targetNamespace="http://tempuri.org/">
2: <wsdl:types>
3: <xsd:schema targetNamespace="http://tempuri.org/Imports">
4: <xsd:import schemaLocation="http://flyservice.vb-net.com/CursUSD.svc?xsd=xsd0" namespace="http://tempuri.org/"/>
5: <xsd:import schemaLocation="http://flyservice.vb-net.com/CursUSD.svc?xsd=xsd1" namespace="http://schemas.microsoft.com/2003/10/Serialization/"/>
6: </xsd:schema>
7: </wsdl:types>
8: <wsdl:message name="ICursUSD_GetCurs_InputMessage">
9: <wsdl:part name="parameters" element="tns:GetCurs"/>
10: </wsdl:message>
11: <wsdl:message name="ICursUSD_GetCurs_OutputMessage">
12: <wsdl:part name="parameters" element="tns:GetCursResponse"/>
13: </wsdl:message>
14: <wsdl:portType name="ICursUSD">
15: <wsdl:operation name="GetCurs">
16: <wsdl:input wsaw:Action="http://tempuri.org/ICursUSD/GetCurs" message="tns:ICursUSD_GetCurs_InputMessage"/>
17: <wsdl:output wsaw:Action="http://tempuri.org/ICursUSD/GetCursResponse" message="tns:ICursUSD_GetCurs_OutputMessage"/>
18: </wsdl:operation>
19: </wsdl:portType>
20: <wsdl:binding name="BasicHttpBinding_ICursUSD" type="tns:ICursUSD">
21: <soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
22: <wsdl:operation name="GetCurs">
23: <soap:operation soapAction="http://tempuri.org/ICursUSD/GetCurs" style="document"/>
24: <wsdl:input>
25: <soap:body use="literal"/>
26: </wsdl:input>
27: <wsdl:output>
28: <soap:body use="literal"/>
29: </wsdl:output>
30: </wsdl:operation>
31: </wsdl:binding>
32: <wsdl:service name="CursUSD">
33: <wsdl:port name="BasicHttpBinding_ICursUSD" binding="tns:BasicHttpBinding_ICursUSD">
34: <soap:address location="http://flyservice.vb-net.com/CursUSD.svc"/>
35: </wsdl:port>
36: </wsdl:service>
37: </wsdl:definitions>
А стоит изменить привязку с basicHttpBinding на wsHttpBinding - как WSDL резко меняется и его уже не опознают клиенты других платформ - JAVA, FLEX и проч.
1: <wsdl:definitions name="CursUSD" targetNamespace="http://tempuri.org/">
2: <wsp:Policy wsu:Id="WSHttpBinding_ICursUSD_policy">
3: <wsp:ExactlyOne>
4: <wsp:All>
5: <wsaw:UsingAddressing/>
6: </wsp:All>
7: </wsp:ExactlyOne>
8: </wsp:Policy>
9: <wsdl:types>
10: <xsd:schema targetNamespace="http://tempuri.org/Imports">
11: <xsd:import schemaLocation="http://flyservice.vb-net.com/CursUSD.svc?xsd=xsd0" namespace="http://tempuri.org/"/>
12: <xsd:import schemaLocation="http://flyservice.vb-net.com/CursUSD.svc?xsd=xsd1" namespace="http://schemas.microsoft.com/2003/10/Serialization/"/>
13: </xsd:schema>
14: </wsdl:types>
15: <wsdl:message name="ICursUSD_GetCurs_InputMessage">
16: <wsdl:part name="parameters" element="tns:GetCurs"/>
17: </wsdl:message>
18: <wsdl:message name="ICursUSD_GetCurs_OutputMessage">
19: <wsdl:part name="parameters" element="tns:GetCursResponse"/>
20: </wsdl:message>
21: <wsdl:portType name="ICursUSD">
22: <wsdl:operation name="GetCurs">
23: <wsdl:input wsaw:Action="http://tempuri.org/ICursUSD/GetCurs" message="tns:ICursUSD_GetCurs_InputMessage"/>
24: <wsdl:output wsaw:Action="http://tempuri.org/ICursUSD/GetCursResponse" message="tns:ICursUSD_GetCurs_OutputMessage"/>
25: </wsdl:operation>
26: </wsdl:portType>
27: <wsdl:binding name="WSHttpBinding_ICursUSD" type="tns:ICursUSD">
28: <wsp:PolicyReference URI="#WSHttpBinding_ICursUSD_policy"/>
29: <soap12:binding transport="http://schemas.xmlsoap.org/soap/http"/>
30: <wsdl:operation name="GetCurs">
31: <soap12:operation soapAction="http://tempuri.org/ICursUSD/GetCurs" style="document"/>
32: <wsdl:input>
33: <soap12:body use="literal"/>
34: </wsdl:input>
35: <wsdl:output>
36: <soap12:body use="literal"/>
37: </wsdl:output>
38: </wsdl:operation>
39: </wsdl:binding>
40: <wsdl:service name="CursUSD">
41: <wsdl:port name="WSHttpBinding_ICursUSD" binding="tns:WSHttpBinding_ICursUSD">
42: <soap12:address location="http://flyservice.vb-net.com/CursUSD.svc"/>
43: <wsa10:EndpointReference>
44: <wsa10:Address>http://flyservice.vb-net.com/CursUSD.svc</wsa10:Address>
45: </wsa10:EndpointReference>
46: </wsdl:port>
47: </wsdl:service>
48: </wsdl:definitions>
В общем лично у меня рабочий конфиг для wsHttpBinding - который бы железно работал на любой платформе - это пока открытый вопрос. В отдельных случаях я добиваюсь совместимости с клиентами других платформ - - предлагая клиенту несколько биндингов - чтобы он мог выбрать подходящий.
Ниже вы видете конфиг, в котором клиенту предлагается два биндинга - basicHttpBinding и customBinding. Этим конфигом мне неоднократно удалось добиваться совместимости со средой PHP. Это конфиг с отладкой (которая в данный момент выключена, чтобы не загаживать диск журналами).
1: <?xml version="1.0"?>
2: <configuration>
3: <connectionStrings>
4: <add name="SQLServer_ConnectionStrings" providerName="Npgsql"
5: connectionString="HOST=192.168.0.21;PORT=5432;PROTOCOL=3;DATABASE=inplat;USER ID=postgres;POOLING=True;CONNECTIONLIFETIME=0;MINPOOLSIZE=1;MAXPOOLSIZE=1024;COMMANDTIMEOUT=200;INTEGRATED SECURITY=False;" />
6: </connectionStrings>
7: <system.web>
8: <customErrors mode="Off"/>
9: <compilation debug="true" strict="false" explicit="true" targetFramework="4.0" />
10: </system.web>
11: <system.serviceModel>
12: <services>
13: <service behaviorConfiguration="dbg1" name="InplatGateway_SERV1.PaycashShopClient">
14: <endpoint binding="basicHttpBinding" bindingConfiguration="PaycashShopServiceSoap"
15: bindingNamespace="" contract="PaycashShopServiceSoap" />
16: </service>
17: </services>
18: <bindings>
19: <basicHttpBinding>
20: <binding name="PaycashShopServiceSoap" closeTimeout="00:01:00"
21: openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
22: allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
23: maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
24: messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
25: useDefaultWebProxy="true">
26: <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
27: maxBytesPerRead="4096" maxNameTableCharCount="16384" />
28: <security mode="None">
29: <transport clientCredentialType="None" proxyCredentialType="None"
30: realm="" />
31: <message clientCredentialType="UserName" algorithmSuite="Default" />
32: </security>
33: </binding>
34: </basicHttpBinding>
35: <customBinding>
36: <binding name="PaycashShopServiceSoap12">
37: <textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
38: messageVersion="Soap12" writeEncoding="utf-8">
39: <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
40: maxBytesPerRead="4096" maxNameTableCharCount="16384" />
41: </textMessageEncoding>
42: <httpTransport manualAddressing="false" maxBufferPoolSize="524288"
43: maxReceivedMessageSize="65536" allowCookies="false" authenticationScheme="Anonymous"
44: bypassProxyOnLocal="false" decompressionEnabled="true" hostNameComparisonMode="StrongWildcard"
45: keepAliveEnabled="true" maxBufferSize="65536" proxyAuthenticationScheme="Anonymous"
46: realm="" transferMode="Buffered" unsafeConnectionNtlmAuthentication="false"
47: useDefaultWebProxy="true" />
48: </binding>
49: </customBinding>
50: </bindings>
51: <client>
52: <endpoint address="http://calc.vb-net.com/"
53: binding="basicHttpBinding" bindingConfiguration="PaycashShopServiceSoap"
54: contract="PaycashShopServiceSoap" name="PaycashShopServiceSoap" />
55: <endpoint address="http://calc.vb-net.com/"
56: binding="customBinding" bindingConfiguration="PaycashShopServiceSoap12"
57: contract="PaycashShopServiceSoap" name="PaycashShopServiceSoap12" />
58: </client>
59: <behaviors>
60: <serviceBehaviors>
61: <behavior name="dbg1">
62: <serviceMetadata httpGetEnabled="true" />
63: <serviceDebug includeExceptionDetailInFaults="true" />
64: </behavior>
65: </serviceBehaviors>
66: </behaviors>
67: <serviceHostingEnvironment multipleSiteBindingsEnabled="false" aspNetCompatibilityEnabled="true" />
68: </system.serviceModel>
69: <system.webServer>
70: <defaultDocument>
71: <files>
72: <add value="PaycashShopClient.svc" />
73: </files>
74: </defaultDocument>
75: <modules runAllManagedModulesForAllRequests="true" />
76: </system.webServer>
77:
78: </configuration>
Основная фишка этого конфига, обеспечивающая совместимость со средой PHP - привязка, которую я назвал PaycashShopServiceSoap12. Именно в режиме customBinding можно выставить несколько важных параметров, недоступных в стандартных режимах :
- authenticationScheme="Anonymous" (другие режимы None, Digest, Negotiate, Ntlm, IntegratedWindowsAuthentication, Basic, Anonymous). В результате многочисленных, долгих и мучительных экспериментов я установил что Anonymous лучше None работает со средой PHP.
- messageVersion="Soap12" (другие режимы None, Soap11, Soap12, Soap11WSAddressing10, Soap12WSAddressing10, Soap11WSAddressingAugust2004, Soap12WSAddressingAugust2004). Вручную выставить версию SOAP тоже крайне важно. Многие клиенты работают лишь со строго определенной версией SOAP:
К счастью конфиг, создаваемый по умолчанию в Visual Studio (basicHttpBinding) - вполне достаточно хорошо совместим с немикрософтовскими средами - Создание асинхронного прокси для обращения к WCF средствами Adobe flex builder - здесь вы можете увидеть мою методику тестирования совместимости WCF-сервисов со средой FLEX.
А мою методику тестирования совместимости WCF-сервисов с тремя JAVA-стеками - Axis, CXF, Metro - вы можете посмотреть в моей заметке JAVA-клиенты Windows Communication Foundation.
А если вы пока начинающий программист и еще не понимате о какой совместимости вообще идет речь в этой заметке - почитайте пока как вообще строить WCF-сервисы - Как сделать SOAP/WSDL-вебсервис на ASP.NET/MONO для вызова его из FLEX.
|