我和我的团队正在开发一个相当大的应用程序,其中包含许多基于 WCF NetTCP 的服务。该系统将在其下运行的 Windows 服务不是本地帐户,而是标准域用户(在托管该服务的服务器上具有管理员权限)。在测试连接过程中,我遇到了 SSPI 调用失败的问题。基于几个小时的研究,这导致我在客户端配置中遗漏了以下行:

<identity>
     <userPrincipalName value="MACHINE\user" />
</identity>

使用这个的问题是我不使用 VS 或 svcutil 来生成此服务的客户端/代理 - 所使用的代理完全用代码编写,并且它们继承 System.ServiceModel.ClientBase。我相信选择此选项的最初原因是我们可以使用通过栅栏两侧的服务的完全相同的 DataMember 对象 - 第三方团体不需要连接到我们的服务,所以这不是问题。

当我没有在标准 system.serviceModel 配置部分中指定端点时,有谁知道我在客户端中设置 userPrincipalName 的方法(代码或通过配置)?

这是我的客户端 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中,以端点的名称在配置中查找。

也就是说,您当然可以通过代码填充端点身份,您只需要创建正确的端点定位派生类,然后将其附加到实例化代理类时使用的端点address对象。这样的事情:

EndpointIdentity epid = EndpointIdentity.CreateUpnIdentity("user@domain.fqdn");
EndpointAddress epaddr = new EndpointAddress(uri, epid);

MyClient client = new MyClient(epaddr);

其他提示

尽管我可能不会直接回答您的问题,但要在栅栏两侧使用相同的数据成员,您不需要手动创建代理。您要做的就是使用 svcutil 生成代理,并传入数据成员为 /r 的 dll

例如

svcutil http://localhost/service/service.svc /r:AssemblyThatHasDataMembers.dll /out:ServiceProxy.cs

这样,数据成员类型就不会在 ServiceProxy.cs 文件中重复。您可以通过传递 wsdl/xsd (真正的契约优先方法)来广泛定制它,使用 /ct 定制集合类型等。

这将为您节省大量手动制作代理的时间,同时避免您可能遇到的上述问题,因为一切都会成为库存标准。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top