我正在编写带有“状态工具”的Windows服务。该服务托管一个名为管道端点的WCF,用于进程间通信。通过命名管道,状态工具可以定期查询服务以获取最新的“状态”。
在我的开发机器上,我有多个IP地址;其中一个是具有192.168.1.XX地址的“本地”网络。另一个是“公司”网络,具有10.0.X.XX地址。 Windows服务在单个IP地址上收集UDP多播流量。
到目前为止,Windows服务只要使用“192.168.1.XX”地址就可以正常工作。它始终正确地向客户报告状态。
一旦我切换到另一个“公司”IP地址(10.0.X.XX)并重新启动服务,我在检索状态时会得到连续的“CommunicationExceptions”:
"There was an error reading from the pipe: The pipe has been ended. (109, 0x6d)."
现在,我不认为UDP客户端的“声明的”IP地址应该与Named-Pipe接口的功能有关;它们是完全独立的应用程序!
以下是相关的WCF配置部分:
//On the Client app:
string myNamedPipe = "net.pipe://127.0.0.1/MyNamedPipe";
ChannelFactory<IMyService> proxyFactory =
new ChannelFactory<IMyService>(
new NetNamedPipeBinding(),
new EndpointAddress(myNamedPipe));
//On the Windows Service:
string myNamedPipe = "net.pipe://127.0.0.1/MyNamedPipe";
myService = new MyService(myCustomArgs);
serviceContractHost = new ServiceHost(myService );
serviceContractHost.AddServiceEndpoint(
typeof(IMyService),
new NetNamedPipeBinding(),
myNamedPipe);
serviceContractHost.Open();
我不认为这是一个'权限'问题 - 我正在运行具有管理权限的客户端 - 但也许有一些特定于域的原因导致了这一点?
事实证明,IP地址是一个完整的红鲱鱼。
异常的真正原因是WCF服务返回了无效的Enum值。
我的枚举是这样定义的:
[DataContract]
public enum MyEnumValues : Byte
{
[EnumMember]
Enum1 = 0x10,
[EnumMember]
Enum2 = 0x20,
[EnumMember]
Enum3 = 0x30,
[EnumMember]
Enum4 = 0x40,
}
表面看起来很好。
但是底层服务报告的原始状态是字节值“0”,并且没有相应的Enum值可以将其强制转换。
一旦我确保Enum值全部有效,该工具就像圣诞树一样点亮。
如有疑问,请假设您的WCF数据无效。
此异常意味着服务器端存在序列化问题。
可以通过查看跟踪文件(svclog)来解决此问题。要打开跟踪,请使用以下配置:
<system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="false">
<listeners>
<add name="traceListener" />
</listeners>
</source>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add name="traceListener" />
</listeners>
</source>
</sources>
<sharedListeners>
<add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData="C:\Remos\Log\WcfTraceServer.svclog" />
</sharedListeners>
</system.diagnostics>
就我而言,我正在序列化一个不在枚举中的值。
有同样的问题There was an error reading from the pipe: Unrecognized error 109 (0x6d).
<netNamedPipeBinding> <security mode="None"></security>...
(没有通信)两者都有相同的顶部错误消息。
增加服务器和客户端绑定的时间会使问题再次出现。
绑定时间设置得太低:
sendTimeout="00:00:05" receiveTimeout="00:00:05"
堆栈跟踪:
at System.ServiceModel.Channels.StreamConnection.Read(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout)
at System.ServiceModel.Channels.SessionConnectionReader.Receive(TimeSpan timeout)
at System.ServiceModel.Channels.SynchronizedMessageSource.Receive(TimeSpan timeout)
at System.ServiceModel.Channels.TransportDuplexSessionChannel.Receive(TimeSpan timeout)
at System.ServiceModel.Channels.TransportDuplexSessionChannel.TryReceive(TimeSpan timeout, Message& message)
at System.ServiceModel.Dispatcher.DuplexChannelBinder.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
有时这个错误是由对象的多态特征引起的。例如,以下service的方法将返回人员列表:
[OperationContract]
List<Person> GetEmployee();
如果我们有继承自Person类的Supervisor类,并且上面的方法尝试返回Supervisor对象,则WCF序列化器类无法解释响应,因此会引发此错误。 该问题的解决方案是使用“已知类型”或“服务已知类型”。我们必须指定隐式对象可以使用方法或服务进行交互。对于我的示例,我们可以将ServiceKnownType属性放在方法或服务声明中,如下代码:
[OperationContract]
[ServiceKnownType(typeof(Supervisor))]
List<Person> GetEmployee();
当返回的有效负载太大时,这发生在我的WCF服务中。通过在app.config中的serviceBehavior中添加它来修复它:
<dataContractSerializer maxItemsInObjectGraph="[some big number]" />
当服务操作抛出并且通道实际出现故障时,我收到此错误。在您的情况下,您已经验证了服务操作正确完成并且只返回了投票,但如果有疑问,请确保服务操作运行正常。
我有很多没有设置{}的属性。添加这个解决了我的问题。
我有这个问题,因为我使用的是older tutorial,并尝试以编程方式进行配置。
我缺少的部分是提供元数据端点(thank you, this post!)。
ServiceMetadataBehavior serviceMetadataBehavior =
host.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (serviceMetadataBehavior == null)
{
serviceMetadataBehavior = new ServiceMetadataBehavior();
host.Description.Behaviors.Add(serviceMetadataBehavior);
}
host.AddServiceEndpoint(
typeof(IMetadataExchange),
MetadataExchangeBindings.CreateMexNamedPipeBinding(),
"net.pipe://localhost/PipeReverse/mex"
);