2

我构建了一个解析应用程序,它读取 xml 文件并使用NPOI库填充 Excel 工作簿。最初,我将它作为我的 .net Web 应用程序的一部分,并从 NPOI 获取 MemoryStream 并将其写入 Response 对象,以便浏览器下载它。此后,我将解析移至 Windows 服务中托管的 WCF netTcp 服务。通信效果很好,但是当我从 WCF 服务返回 MemoryStream 并将其写入响应时,我收到以下错误:

Microsoft JScript 运行时错误:Sys.WebForms.PageRequestManagerParserErrorException:无法解析从服务器接收到的消息。

我的问题是:当流从 wcf 服务传递到我的客户端时会发生什么情况?该流(理论上)与我最初写入响应的 NPOI 中的流完全相同。我需要对客户端进行任何特殊处理才能完成这项工作吗?

这是我的客户端代码:(在 Response.End() 抛出异常

string filename = "test.xls";

ms = client.GetExportedFile();
byte[] b = ms.ToArray();

ms.Flush();
ms.Close();

Response.Clear();
Response.ContentType = "application/vnd.ms-excel";
Response.AddHeader( "Content-Disposition", string.Format( "attachment;filename={0}", filename ) );
Response.AddHeader( "Content-Length", b.Length.ToString() );
Response.BinaryWrite( b );
Response.End();
4

3 回答 3

2

您似乎重新运行流以请求使用更新面板更新部分页面(搜索 Sys.WebForms.PageRequestManagerParserErrorException 以查找有关异常的更多详细信息)。

确保您仅将流重新发送到整页请求(由浏览器本身发出的 GET/POST,而不是由页面上需要某种特定类型响应的某些脚本发出)。

于 2011-01-04T16:59:39.407 回答
1

我在这里找到了解决方案。这是我的冗长答案,以防将来对某人有所帮助。首先,netTcp 不支持真正的流式传输,只支持缓冲。文章指出只有 basicHttp 支持流式传输,但事实并非如此,因为我已经使用 wsHttp 成功测试了这一点。在我的客户端配置文件中,我现在有 2 个绑定定义;1 用于 netTcp,另一个用于 wsHttp(对于我所有的非流式通信,我仍然想使用 netTcp)。如果使用 basicHttp,则需要将 'transferMode' 属性设置为 'Streamed' - wsHttp 不允许该属性。

然后我必须在我的服务中定义一个新的 DataContract,它定义了一个我定义为 MessageBodyMember 的成员。该成员属于 MemoryStream 类型:

[MessageContract]
public class FileDownloadMessage
{
    [MessageBodyMember( Order = 1 )]
    public System.IO.MemoryStream FileByteStream;
}

然后对于最初返回 MemoryStream 的 OperationContract,我修改为返回新的 FileDownloadMessage 数据合约:

[OperationContract]
FileDownloadMessage GetExportedFile();

该合同的实施是:

public FileDownloadMessage GetExportedFile()
{
    FileDownloadMessage f = new FileDownloadMessage();
    f.FileByteStream = new MemoryStream();

    if ( ProgressMonitor.Status == ProcessStatus.CompletedReadyForExport )
    {
        f.FileByteStream = ProgressMonitor.ExportedFileData;

        ProgressMonitor.Status = ProcessStatus.Ready;
    }
    else
    {
        f.FileByteStream = null;
    }

    return f;
}

现在 WCF 服务正在返回没有任何其他随附元数据的 Stream,因此我的网页的 Response 对象可以正确解析流:

MemoryStream ms = new MemoryStream();
string filename = "test.xls";

// the code file from the wcf service includes a get method to get the 
// MessageBodyMember directly
ms = streamingClient.GetExportedFile();
byte[] b = ms.ToArray();

ms.Flush();
ms.Close();

Response.Clear();
Response.ContentType = "application/vnd.ms-excel";
Response.AddHeader( "Content-Disposition", string.Format( "attachment;filename={0}", filename ) );
Response.AddHeader( "Content-Length", b.Length.ToString() );
Response.BinaryWrite( b );
Response.End();

我的配置看起来像:

<wsHttpBinding>
    <binding name="WSHttpBindingEndPoint" 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="655360"
            messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
            allowCookies="false">
        <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="1638400"
                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" />
        </security>
    </binding>
</wsHttpBinding>
<netTcpBinding>
    <binding name="NetTcpBindingEndPoint" closeTimeout="00:01:00"
        openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
        transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions"
        hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="524288"
        maxBufferSize="655360" maxConnections="10" maxReceivedMessageSize="655360">
        <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="1638400"
            maxBytesPerRead="4096" maxNameTableCharCount="16384" />
        <reliableSession ordered="true" inactivityTimeout="00:10:00"
            enabled="false" />
        <security mode="Transport">
            <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
            <message clientCredentialType="Windows" />
        </security>
    </binding>
</netTcpBinding>
于 2011-01-04T17:01:55.580 回答
0

如果您使用的是 IE,可以尝试一些事情;显然,与其他浏览器相比,它从内容类型中推断出的数据更少:

  • 指定公共 Pragma 标头和必须重新验证的 CacheControl 标头。

  • 尝试明确指定内容传输编码:Response.AddHeader("Content-Transfer-Encoding","binary");.

于 2011-01-04T16:24:54.377 回答