Прокси-сервер WCF и имя пользователяPrincipalName
-
11-09-2019 - |
Вопрос
У нас есть довольно большое приложение, которое мы с командой разрабатываем и которое содержит ряд служб на базе WCF NetTCP.Служба Windows, под которой будет работать эта система, будет не локальной учетной записью, а обычным пользователем домена (с правами администратора на серверах, на которых размещена служба).В середине тестирования подключения я столкнулся с проблемой, из-за которой вызовы SSPI завершались неудачно.Основываясь на нескольких часах исследований, это привело меня к тому, что я пропустил следующую строку в конфигурации моего клиента:
<identity>
<userPrincipalName value="MACHINE\user" />
</identity>
Проблема с этим заключается в том, что я не использую VS или svcutil для создания клиента/прокси для этой службы - используемые прокси полностью написаны в коде и наследуют System.ServiceModel.ClientBase.Я считаю, что первоначальная причина, по которой был выбран этот вариант, заключалась в том, чтобы мы могли использовать одни и те же объекты DataMember, которые проходят через службы по обе стороны забора - сторонним группам не нужно будет подключаться к нашим службам, поэтому это не было проблемой. .
Кто-нибудь знает, как мне установить userPrincipalName в клиенте (код или через конфигурацию), когда у меня нет конечных точек, указанных в стандартном разделе конфигурации system.serviceModel?
Вот как выглядит мой файл web.config на стороне клиента:
<system.serviceModel>
<diagnostics>
<messageLogging logEntireMessage="true" logMalformedMessages="true"
logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true" />
</diagnostics>
<behaviors>
<serviceBehaviors>
<behavior name="includeExceptions">
<serviceDebug includeExceptionDetailInFaults="true"/>
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_Default" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="Infinite" sendTimeout="01:00:00" portSharingEnabled="true" transferMode="Buffered" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="Transport">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign"/>
</security>
</binding>
</netTcpBinding>
</bindings>
</system.serviceModel>
Решение
Создание прокси вручную не мешает вам поместить конфигурацию в файл конфигурации;вам просто нужно предоставить правильную перегрузку конструктора в вашем прокси-классе, производном от ClientBase, который делегирует функции правильный конструктор в ClientBase, который принимает имя конечной точки для поиска в конфигурации.
Тем не менее, вы, конечно, можете заполнить идентификатор конечной точки с помощью кода, вам просто нужно создать правильный тип класса, производного от EndpointIdentity, и прикрепить его к объекту EndpointAddress, который вы используете при создании экземпляра прокси-класса.Что-то вроде этого:
EndpointIdentity epid = EndpointIdentity.CreateUpnIdentity("user@domain.fqdn");
EndpointAddress epaddr = new EndpointAddress(uri, epid);
MyClient client = new MyClient(epaddr);
Другие советы
Хотя я, вероятно, не отвечаю на ваш вопрос напрямую, чтобы использовать один и тот же элемент данных по обе стороны забора, вам не нужно создавать прокси вручную.Что вы делаете, так это создаете свои прокси с помощью svcutil и передаете dll, в котором есть ваш элемент данных как /r.
например
svcutil http://localhost/service/service.svc /r:AssemblyThatHasDataMembers.dll /out:ServiceProxy.cs
При этом типы элементов данных не повторяются в файле ServiceProxy.cs.Вы можете широко настроить это, передав wsdl/xsd (подход «сначала настоящий контракт»), настроив типы коллекций с помощью /ct и т. д. и т. п.
Это сэкономит вам много часов на создание прокси вручную и в то же время позволит избежать проблем, подобных описанным выше, с которыми вы можете столкнуться, поскольку тогда все становится стандартным.