对流终结点的WCF服务调用在第三次调用时失败



我在这里得到的东西的快速概述:

WCF Soap服务正在HTTPS上运行,消息凭据类型为certificate。我有两个端点(除了mex),一个用于正常的服务调用,另一个用于流文件。这是我的服务web.config(编辑了一些项目名称):

<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpointBinding">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
<basicHttpBinding>
<binding name="streamBinding" transferMode="Streamed" messageEncoding="Mtom" maxReceivedMessageSize="2147483646">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>        
</bindings>
<services>
<service behaviorConfiguration="Services.Behavior" name="MyInterface">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" name="wsHttpEndpoint" contract="IMyInterface" />
<endpoint address="stream" binding="basicHttpBinding" bindingConfiguration="streamBinding" name="streamEndpoint" contract="IMyInterface" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="Service.Behavior">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<dataContractSerializer maxItemsInObjectGraph="2147483646" />
<serviceCredentials>
<serviceCertificate findValue="CN=Server.Temp.Dev" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>

该服务有一个方法DownloadDocument,我正在测试它。这是签名:

DocumentDownloadResponse DownloadDocument(DocumentDownloadRequest请求);

值得注意的是,当传入的数据无效时,服务会抛出异常,而DownloadDocument会捕获这些异常并在响应对象中传回错误消息。

DocumentDownloadRequest如下所示:

[MessageContract]
public class DocumentDownloadRequest
{
[MessageHeader]
public string SecurityToken { get; set; }
[MessageHeader]
public string LoginName { get; set; }
[MessageHeader]
public string DocumentId { get; set; }
}

和下载文档响应:

[MessageContract]
public class DocumentDownloadResponse : ServiceResponse<Stream>
{
public DocumentDownloadResponse()
{
Data = Stream.Null;
}
[MessageHeader(MustUnderstand = true)]
public bool Success { get; set; }
[MessageHeader(MustUnderstand = true)]
public string ErrorMessage { get; set; }
[MessageBodyMember(Order = 1)]
public Stream Data { get; set; }
}

以下是我在客户端的称呼:

var soapServiceClient = new SoapServiceClient("streamEndpoint");
bool success;
Stream stream;
string errorMessage =
soapServiceClient.DownloadDocument(documentId, loginName, securityToken, out success, out stream);
serviceClient.Close();

其中SecurityToken和LoginName是需要验证的项。奇怪的是,从我的测试客户端,当我使用有效数据调用DownloadDocument时,我可以随心所欲地完美下载该文件。但是,如果传入无效的LoginName或SecurityToken,则会收到指示错误数据的错误消息(正如预期的那样)。但是,如果我传入无效数据3次,客户端就会超时。在本地运行服务我没有遇到这个问题,一切都按预期运行。奇怪的是,当我开着小提琴手跑步时,我没有遇到这个问题。当我在开发服务器上运行该服务时,我会遇到问题。

开发服务器上的配置与我在本地运行的配置相匹配。使用SvcTraceTool,我没有看到任何错误,只是它只记录了前两次成功的调用,而没有记录失败的调用。这几乎让我觉得端点只是以某种方式自行关闭了。

悬崖:

1) 具有2个端点的服务,其中一个if正在流式传输(我关心的那个)。2) 能够使用流式端点调用方法下载具有有效数据的文件3) 服务正确捕获坏数据2次,第3次挂起。SvcTraceTool中没有日志,客户端超时。

有什么想法吗?

感谢

为了回答Rodrigo,我想我会发布更多细节:

首先,将您生成的代理类封装在类似这样的东西中,以正确处理错误:

public class ProxyWrapper<TServiceClientType, TResultType>
where TServiceClientType : class, ICommunicationObject
{
private static string _endPoint;
public ProxyWrapper(string endPoint = "")
{
_endPoint = endPoint;
}
public TResultType Wrap(Func<string, TServiceClientType> constructWithEndpoint,
Func<TServiceClientType, TResultType> codeBlock)
{
TResultType result = default(TResultType);
TServiceClientType client = default(TServiceClientType);
try
{
client = constructWithEndpoint(_endPoint);
result = codeBlock(client);
client.Close();
}
catch (Exception)
{
if (client != null)
{
client.Abort();
}
throw;
}
return result;
}
}

然后,我有一个客户端类,它封装了服务调用。这是下载文档的方法:

public MyServiceResponse<Stream> DownloadDocument(string loginName,
string documentId)
{
var proxyWrapper = new MyProxyWrapper<DocumentDownloadResponse>(StreamEndpoint);
DocumentDownloadResponse response =
proxyWrapper.Wrap((client) =>
{
Stream data;
bool success;
string errorMessage = client.DownloadDocument(documentId, loginName,
out success,
out data);
return new DocumentDownloadResponse
{
Data = data,
Success = success,
ErrorMessage = errorMessage
};
});
var result = new MyServiceResponse<Stream>
{
Success = response.Success,
ErrorMessage = response.ErrorMessage
};
if (!response.Success)
{
result.Data = null;
response.Data.Close();
}
else
{
result.Data = response.Data;
}
return result;
}

注意:MyProxyWrapper继承自ProxyWrpper,并指定了WCF客户端代理类。现在实际的调用看起来是这样的:

var myClient = new MyClient();
var downloadDocumentResponse = myClient.DownloadDocument(someId);
using (
Stream output =
File.OpenWrite(someFilePath))
{
downloadDocumentResponse.Data.CopyTo(output, 2048);
downloadDocumentResponse.Data.Close();
}

请注意,我在流上调用.Close()的两个区域,一次是在写入文件后,另一次是响应。成功==错误。

相关内容

  • 没有找到相关文章

最新更新