我们正在将.Net Remoting代码库转换为Wcf。我们之前使用的一小部分方法使用客户端和服务器之间的Stream
实例来传输大文件等。客户端和服务器都是IIS中托管的Web应用程序。
最初,我们在Wcf上使用这些方法时遇到问题,因为httpTransport默认使用buffered传输模式,因此不支持Stream
个对象作为参数或返回值。将传输配置更改为使用StreamedResponse
(或Streamed
,StreamedResponse
加StreamedRequest
)后,我们会在每次首次调用服务时遇到异常(例如,编译服务提供程序,或重新启动IIS):
The input source is not correctly formatted.
[XmlException: The input source is not correctly formatted.]
System.Xml.XmlExceptionHelper.ThrowXmlException(XmlDictionaryReader reader, String res, String arg1, String arg2, String arg3) +815516
System.Xml.XmlExceptionHelper.ThrowInvalidBinaryFormat(XmlDictionaryReader reader) +34
System.Xml.XmlBinaryReader.ReadNode() +2367693
System.ServiceModel.Channels.Message.ReadFromBodyContentsToEnd(XmlDictionaryReader reader, EnvelopeVersion envelopeVersion) +65
System.ServiceModel.Dispatcher.OperationFormatter.DeserializeBodyContents(Message message, Object[] parameters, Boolean isRequest) +319
System.ServiceModel.Dispatcher.OperationFormatter.DeserializeReply(Message message, Object[] parameters) +741
[CommunicationException: Error in deserializing body of reply message for operation '[MyMethod]'. The input source is not correctly formatted.]
[webforms page 'Page_Load' stacktrace]
我们目前正在使用自定义绑定堆栈(通过http启用二进制编码),配置如下:
<system.serviceModel>
<bindings>
<customBinding>
<binding>
<binaryMessageEncoding/>
<httpTransport transferMode="StreamedResponse" maxReceivedMessageSize="2147483647"/>
</binding>
</customBinding>
</bindings>
...
</system.serviceModel>
如何才能找到仅在主机Web应用程序需要启动时才会发生这种情况的原因?当我在此错误后立即刷新页面时,所有其他页面的所有内容似乎都能正常工作。也许它与某种程度上是超时相关的,因为在重新编译/池循环/ webconfig更改/等之后唤醒服务器需要时间?
更新
我测试了将所有超时增加到客户端和服务器绑定上的默认值,如下所示:
<binding closeTimeout="10:00:00"
openTimeout="10:00:00"
receiveTimeout="10:00:00"
sendTimeout="10:00:00">
<binaryMessageEncoding />
<httpTransport transferMode="Streamed" maxReceivedMessageSize="2147483647" />
</binding>
但似乎没有任何改变,因为在服务器更新后,我仍然在第一次访问时遇到相同的异常。
更新2:
我刚刚发现this post这似乎与我遇到的问题相同。作者说:
我忘了提到这种情况每次只发生一次 服务器已启动。
他的问题似乎是客户端和服务器端点堆栈之间的不匹配,但这不是我的情况。
答案 0 :(得分:0)
进一步自定义环境后,此错误停止发生。
我所做的是从配置文件中的传输组件中删除参数。
然后我创建了一个自定义行为,根据它的契约接口动态地将它添加到端点:如果契约有任何返回或接收Stream对象的方法,我检查它的端点绑定并添加Streamed
模式到绑定的httpTransport组件,如下所示:
public sealed class DynamicStreamingEndpointBehavior : IEndpointBehavior
{
private bool m_contractHasStream;
void IEndpointBehavior.Validate(ServiceEndpoint _endpoint)
{
IEnumerable<MethodInfo> streamMethods =
from method in _endpoint.Contract.ContractType.GetMethods()
where method.GetCustomAttribute<OperationContractAttribute>() != null && (
typeof (Stream).IsAssignableFrom(method.ReturnType) ||
method.GetParameters()
.Select(_parameter => _parameter.ParameterType)
.Any(_type => typeof (Stream).IsAssignableFrom(_type)))
select method;
m_contractHasStream = streamMethods.Any();
}
void IEndpointBehavior.AddBindingParameters(ServiceEndpoint _endpoint,
BindingParameterCollection _bindingParameters) {}
void IEndpointBehavior.ApplyDispatchBehavior(ServiceEndpoint _endpoint, EndpointDispatcher _endpointDispatcher)
{
if (!m_contractHasStream) return;
BindingElementCollection bindingElements = _endpoint.Binding.CreateBindingElements();
bindingElements.OfType<HttpTransportBindingElement>().Single().TransferMode =
TransferMode.Streamed;
_endpoint.Binding = new CustomBinding(bindingElements);
}
void IEndpointBehavior.ApplyClientBehavior(ServiceEndpoint _endpoint, ClientRuntime _clientRuntime)
{
if (!m_contractHasStream) return;
BindingElementCollection bindingElements = _endpoint.Binding.CreateBindingElements();
bindingElements.OfType<HttpTransportBindingElement>().Single().TransferMode =
TransferMode.Streamed;
_endpoint.Binding = new CustomBinding(bindingElements);
}
}
然后,通过创建自定义扩展程序元素,我可以在config中全局配置它:
public sealed class DynamicStreamingBehaviorElement : BehaviorExtensionElement
{
public override Type BehaviorType
{
get { return typeof (DynamicStreamingEndpointBehavior); }
}
protected override object CreateBehavior()
{
return new DynamicStreamingEndpointBehavior();
}
}
以下是最终配置:
<system.serviceModel>
<extensions>
<behaviorExtensions>
...
<add name="dynamicStreaming"
type="[namespace].DynamicStreamingBehaviorElement, [assembly]"/>
...
</behaviorExtensions>
</extensions>
...
<behaviors>
<endpointBehaviors>
<behavior>
...
<dynamicStreaming />
...
</behavior>
</endpointBehaviors>
...
</behaviors>
</system.serviceModel>
如果我将Streamed
模式保留在所有端点上,我仍然不确定为什么会出现问题。