WCF - 如果服务器抛出FaultException,则从客户端到服务器的中止流

时间:2017-09-27 14:19:18

标签: .net vb.net wcf

我们有一个WCF服务,它接受来自客户端的流(客户端将文件上传到服务器)。但是,如果服务器在流之前或期间抛出FaultException,则客户端只进行流式传输直到结束,无论何时它从服务器接收到FaultException - 浪费时间和时间。客户的带宽。

类似的问题:

How to Abort a WCF File Upload from the Server-Side Method

采取以下(简化的WCF服务)

Try
    Dim sourceStream As Stream = request.FileByteStream
    Dim uploadFolder As String = "C:\upload\"
    Dim filePath As String = Path.Combine(uploadFolder, request.FileName)

    Using targetStream = New FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None)
        sourceStream.CopyTo(targetStream)
        targetStream.Close()
        sourceStream.Close()
    End Using
Catch ex As Exception
    Throw New FaultException(Of JP_WCF_Fault)(New JP_WCF_Fault(8, ex.Message, ex.ToString), ex.Message)
End Try

示例服务器方法:

Dim fileInfo As New System.IO.FileInfo(filePath)
Dim startTime As DateTime = DateTime.Now
Console.WriteLine("Starting V2 upload: " + DateTime.Now.ToString())

Dim JPCS As New JP_WCFService.JP_WCFClient()

Using stream As New System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read)
    Using uploadStreamWithProgress As New JP_StreamWithProgress(stream)
        AddHandler uploadStreamWithProgress.ProgressChanged, AddressOf uploadStreamWithProgress_ProgressChanged
        Try
            JPCS.UploadFile(fileInfo.Name, fileInfo.Length, uploadStreamWithProgress)
        Catch ex As FaultException(Of JP_WCFService.JP_WCF_Fault)
            Console.WriteLine("Upload Error: " & ex.Detail.Message & " (EventID: " & ex.Detail.EventID.ToString & ")")
        End Try
    End Using
End Using
Dim endTime As DateTime = DateTime.Now
Dim durationInMS As Double = (endTime - startTime).TotalMilliseconds
Console.WriteLine(vbCr & "V2 Upload Completed: " + DateTime.Now.ToString() + " (" + durationInMS.ToString() + ")")
JPCS.Close()

示例客户端方法:

<system.serviceModel>
    <bindings>
        <customBinding>
            <binding name="JP_WCFBinding">
                <!-- maxReceivedMessageSize 600MB, maxBufferSize 2MB -->
                <binaryMessageEncoding compressionFormat="GZip" />
                <httpsTransport transferMode="Streamed" maxReceivedMessageSize="629145600" maxBufferSize="2097152"/>
            </binding>
        </customBinding>
    </bindings>
    <services>
        <service behaviorConfiguration="JP_WCFbehavior" name="JP_WCF.JP_WCFServices">
            <endpoint address="" binding="customBinding" bindingConfiguration="JP_WCFBinding" contract="JP_WCF.IJP_WCF"/>
        </service>
    </services>
    <behaviors>
        <serviceBehaviors>
            <behavior name="JP_WCFbehavior">
                <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
                <serviceDebug includeExceptionDetailInFaults="true" />
            </behavior>
        </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>

的web.config

 <system.serviceModel>
    <bindings>
        <customBinding>
            <binding name="CustomBinding_IJP_WCF">
                <binaryMessageEncoding compressionFormat="GZip" />
                <httpsTransport transferMode="Streamed" />
            </binding>
        </customBinding>
    </bindings>
    <client>
        <endpoint address="https://dev-wcf.localhost/JP_WCF.svc"
            binding="customBinding" bindingConfiguration="CustomBinding_IJP_WCF"
            contract="JP_WCFService.IJP_WCF" name="CustomBinding_IJP_WCF" />
    </client>
</system.serviceModel>

的app.config

d30,d31,d32

2 个答案:

答案 0 :(得分:3)

如果您担心此通话的效果,您可以随时拨打服务器电话,以便在流式传输之前检查此上传的有效性。这样,如果出现问题,您可以避免流式传输文件并避免应用程序中的任何异常状态(也很昂贵)。

因此,您可以相对快速地访问服务器以验证诸如

之类的内容
  1. 有效档案位置
  2. 写入该位置的权限
  3. 文件的大小有效
  4. 任何相关业务规则
  5. 然后,您可以在不尝试使用异常管理应用程序流的情况下拨打电话。请记住:例外情况应该是特殊情况。这样,如果您的应用程序确实引发异常,则意味着发生了非常异常的事情并且速度下降更加可口(因为这种情况理论上会非常罕见)。

答案 1 :(得分:2)

您的客户是否有双工渠道?如果是这样,那么在客户合同上回调就可以直接在文件上传时发送信息。

如果没有,那么这里的一个好方法是使用内存缓冲区以块的形式将数据流传输到服务器。我在下面列举了一些很好的例子。

要点是您将文件拆分为客户端上的块并将其逐块发送到服务器。如果任何块失败,那么它可以重试该块,或者优雅地失败而不再发送任何数据。

这些引用使用StreamWithProgress类来处理客户端上的此逻辑。希望这会有所帮助。

Code Project reference

Simple implementation using StreamWithProgress class