2009-11-25 26 views
0

我已经通过了MSDN WCF - Getting Started Tutorial,直到我试图把客户从一台机器在我的域名转移到另一个在我的域名它去伟大。当我将客户peice移动到我的网络中的其他机器时,它给了我一个SecurityNegotiationException。这是我所做的:如何将MSDN“Self-Hosted”WCF示例从localhost移开?

  1. 我定义了一个服务合约(见下面的代码块1)。
  2. 我实施了服务合同(请参阅下面的代码块2)。
  3. 我创建了一个运行该服务的主机(请参阅下面的代码块3)。
  4. svcutil.exe生成我的代理类和配置文件(请参见下面的代码块4)。
  5. 将输出从4复制到我的客户端项目中。
  6. 我创建了一个客户端连接到我的主机(请参见下面的代码块5)。

当我在自己的机器(SCOTT)上运行服务和客户端时,它工作正常。当我运行我的机器(SCOTT)上的服务和我的虚拟机上运行的客户端(SCOTT-VM)失败与以下堆栈跟踪:

Unhandled Exception: System.ServiceModel.Security.SecurityNegotiationException: SOAP security negotiation with 'http://scott:8000/ServiceModelSamples/Service/CalculatorService' for target 'http://scott:8000/ServiceModelSamples/Service/CalculatorService' failed. See inner exception for more details. ---> System.ComponentModel.Win32Exception: Security Support Provider Interface (SSPI) authentication failed. The server may not be running in an account with identity 'host/scott'. If the server is running in a service account (Network Service for example), specify the account's ServicePrincipalName as the identity in the EndpointAddress for the server. If the server is running in a user account, specify the account's UserPrincipalName as the identity in the EndpointAddress for the server. 
    at System.ServiceModel.Security.WindowsSspiNegotiation.GetOutgoingBlob(Byte[] incomingBlob) 
    at System.ServiceModel.Security.SspiNegotiationTokenProvider.GetNextOutgoingMessageBody(Message incomingMessage, SspiNegotiationTokenProviderState sspiState) 
    at System.ServiceModel.Security.IssuanceTokenProviderBase`1.GetNextOutgoingMessage(Message incomingMessage, T negotiationState) 
    at System.ServiceModel.Security.IssuanceTokenProviderBase`1.DoNegotiation(TimeSpan timeout) 
    --- End of inner exception stack trace --- 

Server stack trace: 
    at System.ServiceModel.Security.IssuanceTokenProviderBase`1.DoNegotiation(TimeSpan timeout) 
    at System.ServiceModel.Security.SspiNegotiationTokenProvider.OnOpen(TimeSpan timeout) 
    at System.ServiceModel.Security.WrapperSecurityCommunicationObject.OnOpen(TimeSpan timeout) 
    at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) 
    at System.ServiceModel.Security.CommunicationObjectSecurityTokenProvider.Open(TimeSpan timeout) 
    at System.ServiceModel.Security.SecurityUtils.OpenTokenProviderIfRequired(SecurityTokenProvider tokenProvider, TimeSpan timeout) 
    at System.ServiceModel.Security.SymmetricSecurityProtocol.OnOpen(TimeSpan timeout) 
    at System.ServiceModel.Security.WrapperSecurityCommunicationObject.OnOpen(TimeSpan timeout) 
    at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) 
    at System.ServiceModel.Channels.SecurityChannelFactory`1.ClientSecurityChannel`1.OnOpen(TimeSpan timeout) 
    at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) 
    at System.ServiceModel.Security.SecuritySessionSecurityTokenProvider.DoOperation(SecuritySessionOperation operation, EndpointAddress target, Uri via, SecurityToken currentToken, TimeSpan timeout) 
    at System.ServiceModel.Security.SecuritySessionSecurityTokenProvider.GetTokenCore(TimeSpan timeout) 
    at System.IdentityModel.Selectors.SecurityTokenProvider.GetToken(TimeSpan timeout) 
    at System.ServiceModel.Security.SecuritySessionClientSettings`1.ClientSecuritySessionChannel.OnOpen(TimeSpan timeout) 
    at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) 
    at System.ServiceModel.Channels.ServiceChannel.OnOpen(TimeSpan timeout) 
    at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) 

Exception rethrown at [0]: 
    at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) 
    at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) 
    at System.ServiceModel.ICommunicationObject.Open(TimeSpan timeout) 
    at System.ServiceModel.ClientBase`1.System.ServiceModel.ICommunicationObject.Open(TimeSpan timeout) 
    at System.ServiceModel.ClientBase`1.Open() 
    at Client.Module1.Main() in C:\Projects\SKUNK\WCFServiceTutorial\Client\Module1.vb:line 11 

(I使用的代码块的上方,使得它会滚动和格式很好,我试图用报价,它是不可读的。)

对于一个训练有素的WCF用户这个堆栈跟踪可能有明显的问题,但我看不出问题。首先,我想解决这个问题。其次,我想知道任何优秀的教程和培训材料。 mark_s有一些伟大的链接in his answer。我已经压缩了我的source code供您审查。

由于



代码块

码块1:

Imports System.ServiceModel 

<ServiceContract(Namespace:="http://Microsoft.ServiceModel.Samples")> _ 
Public Interface ICalculator 

    <OperationContract()> _ 
    Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double 
    <OperationContract()> _ 
    Function Subtract(ByVal n1 As Double, ByVal n2 As Double) As Double 
    <OperationContract()> _ 
    Function Multiply(ByVal n1 As Double, ByVal n2 As Double) As Double 
    <OperationContract()> _ 
    Function Divide(ByVal n1 As Double, ByVal n2 As Double) As Double 
    <OperationContract()> _ 
    Function Sin(ByVal n1 As Double) As Double 

End Interface 

码块2:

Public Class CalculatorService 
    Implements ICalculator 

    Public Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculator.Add 
     Dim result As Double = n1 + n2 
     Console.WriteLine("Received Add({0}, {1})", n1, n2) 
     Console.WriteLine("Return: {0}", result) 
     Return result 
    End Function 

    Public Function Subtract(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculator.Subtract 
     Dim result As Double = n1 - n2 
     Console.WriteLine("Received Subtract({0},{1})", n1, n2) 
     Console.WriteLine("Return: {0}", result) 
     Return result 

    End Function 

    Public Function Multiply(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculator.Multiply 
     Dim result As Double = n1 * n2 
     Console.WriteLine("Received Multiply({0},{1})", n1, n2) 
     Console.WriteLine("Return: {0}", result) 
     Return result 

    End Function 


    Public Function Divide(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculator.Divide 
     Dim result As Double = n1/n2 
     Console.WriteLine("Received Divide({0},{1})", n1, n2) 
     Console.WriteLine("Return: {0}", result) 
     Return result 

    End Function 

    Public Function Sin(ByVal n1 As Double) As Double Implements ICalculator.Sin 
     Dim result As Double = Math.Sin(n1) 
     Console.WriteLine("Received Sin({0})", n1) 
     Console.WriteLine("Return: {0}", result) 
     Return result 
    End Function 
End Class 

代码块3:

Imports System.ServiceModel 
Imports System.ServiceModel.Description 

Module Module1 

    Sub Main() 
     Dim baseAddress As New Uri("http://scott:8000/ServiceModelSamples/Service") 
     Using selfHost As New ServiceHost(GetType(CalculatorService), baseAddress) 
      Try 
       ' Add a service endpoint 
       selfHost.AddServiceEndpoint(GetType(ICalculator), New WSHttpBinding(), "CalculatorService") 
       ' Enable metadata exchange 
       Dim smb As New ServiceMetadataBehavior() 
       smb.HttpGetEnabled = True 
       selfHost.Description.Behaviors.Add(smb) 

       selfHost.Open() 
       Console.WriteLine("The service is ready.") 
       Console.WriteLine("Press <ENTER> to terminate service.") 
       Console.WriteLine() 
       Console.ReadLine() 

       ' Close the ServiceHostBase to shutdown the service. 
       selfHost.Close() 
      Catch ex As Exception 
       Console.WriteLine("An exception occurred: {0}", ex.Message) 
       selfHost.Abort() 
      End Try 
     End Using 

    End Sub 

End Module 

代码块4:从代码块4

C:\> svcutil.exe /language:vb /out:c:\generatedProxy.vb /config:c:\app.config http://scott:8000/ServiceModelSamples/service 

输出:
的app.config:

<?xml version="1.0" encoding="utf-8"?> 
<configuration> 
    <system.serviceModel> 
     <bindings> 
      <wsHttpBinding> 
       <binding name="WSHttpBinding_ICalculator" closeTimeout="00:01:00" 
        openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" 
        bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" 
        maxBufferPoolSize="524288" maxReceivedMessageSize="65536" 
        messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" 
        allowCookies="false"> 
        <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" 
         maxBytesPerRead="4096" maxNameTableCharCount="16384" /> 
        <reliableSession ordered="true" inactivityTimeout="00:10:00" 
         enabled="false" /> 
        <security mode="Message"> 
         <transport clientCredentialType="Windows" proxyCredentialType="None" 
          realm="" /> 
         <message clientCredentialType="Windows" negotiateServiceCredential="true" 
          algorithmSuite="Default" establishSecurityContext="true" /> 
        </security> 
       </binding> 
      </wsHttpBinding> 
     </bindings> 
     <client> 
      <endpoint address="http://scott:8000/ServiceModelSamples/Service/CalculatorService" 
       binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ICalculator" 
       contract="ICalculator" name="WSHttpBinding_ICalculator"> 
       <identity> 
        <userPrincipalName value="{MY_DOMAIN_NAME}" /> 
       </identity> 
      </endpoint> 
     </client> 
    </system.serviceModel> 
</configuration> 

generatedProxy。VB:

'------------------------------------------------------------------------------ 
' <auto-generated> 
'  This code was generated by a tool. 
'  Runtime Version:2.0.50727.4200 
' 
'  Changes to this file may cause incorrect behavior and will be lost if 
'  the code is regenerated. 
' </auto-generated> 
'------------------------------------------------------------------------------ 

Option Strict Off 
Option Explicit On 



<System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0"), _ 
System.ServiceModel.ServiceContractAttribute([Namespace]:="http://Microsoft.ServiceModel.Samples", ConfigurationName:="ICalculator")> _ 
Public Interface ICalculator 

    <System.ServiceModel.OperationContractAttribute(Action:="http://Microsoft.ServiceModel.Samples/ICalculator/Add", ReplyAction:="http://Microsoft.ServiceModel.Samples/ICalculator/AddResponse")> _ 
    Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double 

    <System.ServiceModel.OperationContractAttribute(Action:="http://Microsoft.ServiceModel.Samples/ICalculator/Subtract", ReplyAction:="http://Microsoft.ServiceModel.Samples/ICalculator/SubtractResponse")> _ 
    Function Subtract(ByVal n1 As Double, ByVal n2 As Double) As Double 

    <System.ServiceModel.OperationContractAttribute(Action:="http://Microsoft.ServiceModel.Samples/ICalculator/Multiply", ReplyAction:="http://Microsoft.ServiceModel.Samples/ICalculator/MultiplyResponse")> _ 
    Function Multiply(ByVal n1 As Double, ByVal n2 As Double) As Double 

    <System.ServiceModel.OperationContractAttribute(Action:="http://Microsoft.ServiceModel.Samples/ICalculator/Divide", ReplyAction:="http://Microsoft.ServiceModel.Samples/ICalculator/DivideResponse")> _ 
    Function Divide(ByVal n1 As Double, ByVal n2 As Double) As Double 

    <System.ServiceModel.OperationContractAttribute(Action:="http://Microsoft.ServiceModel.Samples/ICalculator/Sin", ReplyAction:="http://Microsoft.ServiceModel.Samples/ICalculator/SinResponse")> _ 
    Function Sin(ByVal n1 As Double) As Double 
End Interface 

<System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")> _ 
Public Interface ICalculatorChannel 
    Inherits ICalculator, System.ServiceModel.IClientChannel 
End Interface 

<System.Diagnostics.DebuggerStepThroughAttribute(), _ 
System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")> _ 
Partial Public Class CalculatorClient 
    Inherits System.ServiceModel.ClientBase(Of ICalculator) 
    Implements ICalculator 

    Public Sub New() 
     MyBase.New 
    End Sub 

    Public Sub New(ByVal endpointConfigurationName As String) 
     MyBase.New(endpointConfigurationName) 
    End Sub 

    Public Sub New(ByVal endpointConfigurationName As String, ByVal remoteAddress As String) 
     MyBase.New(endpointConfigurationName, remoteAddress) 
    End Sub 

    Public Sub New(ByVal endpointConfigurationName As String, ByVal remoteAddress As System.ServiceModel.EndpointAddress) 
     MyBase.New(endpointConfigurationName, remoteAddress) 
    End Sub 

    Public Sub New(ByVal binding As System.ServiceModel.Channels.Binding, ByVal remoteAddress As System.ServiceModel.EndpointAddress) 
     MyBase.New(binding, remoteAddress) 
    End Sub 

    Public Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculator.Add 
     Return MyBase.Channel.Add(n1, n2) 
    End Function 

    Public Function Subtract(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculator.Subtract 
     Return MyBase.Channel.Subtract(n1, n2) 
    End Function 

    Public Function Multiply(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculator.Multiply 
     Return MyBase.Channel.Multiply(n1, n2) 
    End Function 

    Public Function Divide(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculator.Divide 
     Return MyBase.Channel.Divide(n1, n2) 
    End Function 

    Public Function Sin(ByVal n1 As Double) As Double Implements ICalculator.Sin 
     Return MyBase.Channel.Sin(n1) 
    End Function 
End Class 

代码块5:

Imports System.ServiceModel 

Module Module1 

    Sub Main() 
     'Dim client As MyCalcServiceRef.CalculatorClient = New MyCalcServiceRef.CalculatorClient() 
     '' Step 1: Create an endpoint address and an instance of the WCF Client. 
     Dim epAddress As New EndpointAddress("http://scott:8000/ServiceModelSamples/Service/CalculatorService") 
     Dim Client As New CalculatorClient(New WSHttpBinding(), epAddress) 

     Client.Open() 

     'Step 2: Call the service operations. 
     'Call the Add service operation. 
     Dim value1 As Double = 100D 
     Dim value2 As Double = 15.99D 
     Dim result As Double = client.Add(value1, value2) 
     Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result) 

     'Call the Subtract service operation. 
     value1 = 145D 
     value2 = 76.54D 
     result = client.Subtract(value1, value2) 
     Console.WriteLine("Subtract({0},{1}) = {2}", value1, value2, result) 

     'Call the Multiply service operation. 
     value1 = 9D 
     value2 = 81.25D 
     result = client.Multiply(value1, value2) 
     Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result) 

     'Call the Divide service operation. 
     value1 = 22D 
     value2 = 7D 
     result = client.Divide(value1, value2) 
     Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result) 

     'Call the Sin service operation. 
     value1 = 144D 
     result = client.sin(value1) 
     Console.WriteLine("Sin({0}) = {1}", value1, result) 

     ' Step 3: Closing the client gracefully closes the connection and cleans up resources. 
     client.Close() 

     Console.WriteLine() 
     Console.WriteLine("Press <ENTER> to terminate client.") 
     Console.ReadLine() 
    End Sub 

End Module 
+0

您是否在意为什么会遇到SecurityNegotiationException?或者你只是在寻找教程? – 2009-11-25 04:53:08

+0

**当然**一个自托管的WCF服务可以向全世界开放!谁说不推荐自行托管?一些经验丰富的WCF大师实际上完全主张自我托管是现实生产系统唯一可行的选择...... – 2009-11-25 06:14:54

+0

我写这个问题的时候已经很晚了,所以它不是很好。我在那里没有一个很棒的“问题”,只是我的一些随笔。我今天会重述一遍,看看自那之后是否有更多。我还会发布我的完整示例(包括源代码)和我的完整例外。感谢迄今为止所有的答案! – Scott 2009-11-25 14:42:08

回答

2

有一吨好WCF材料在那里 - 它只是一个:-)

发现它的问题

然后有很多我关注的博客,当然还有MSDN杂志中的“Service Station”专栏e(通常是更高级的中级到高级主题)

+0

谢谢!开发人员中心WCF屏幕演示非常有帮助。我将我的绑定切换到'basicHttpBinding'并使其工作。再次感谢! – Scott 2009-11-25 18:15:21

3

“自托管服务”(应用程序中的EXE一个运行)可以像一个在IIS或托管作为向世界开放网络服务。这完全取决于你使用的绑定。示例显示使用TCP/IP的WSHttpBinding。像Windows上的任何普通的基于TCP的服务器(包括IIS)一样,除非类似防火墙的东西阻止访问,否则这将向全世界开放。唯一的区别是这些示例绑定到端口8000而不是80,因为默认情况下IIS会这样做(这些示例可能会这样做以避免与IIS发生冲突的可能性)。

您需要准确追踪您为什么得到SecurityNegotiationException。默认情况下,WSHttpBinding上启用了安全功能,但可以关闭这些功能。一般来说,客户端和服务器应该位于同一个域中,否则需要做额外的工作才能让它们成功进行身份验证。

这得到一些点击:https://stackoverflow.com/search?q=SecurityNegotiationException

+0

这并不能真正回答我的问题。我知道应用程序为世界打开一个端口(这些示例使用端口8000)。但是,如果我遇到问题,请在另一台机器上运行客户端示例,然后运行服务示例。看到我上面的链接。遵循上面的例子,我需要做些什么才能将客户端移动到不同的机器上? – Scott 2009-11-25 03:46:55

+0

它“应该”只是工作,但有很多可能出错。你需要弄清楚为什么你会得到这个例外。查看链接。您可能会考虑发布完整的异常详情和堆栈跟踪以获得更多帮助。 – 2009-11-25 03:54:34