none
How to abort stream from client to server if server throws a FaultException RRS feed

  • Question

  • Hello there,

    I've asked this on StackOverflow but not had much luck, hope you guys can help me.

    We have a WCF service that accepts a stream from a client (client uploading a file to server). However, if the server throws a FaultException before or during the stream the client just carries on streaming until the end regardless, at which point it receives the FaultException from the server - wasting time & bandwidth for the client.

    For example, the client streams a 500MB file over ADSL & it can take 30 minutes, if for whatever reason the server needs to abort the stream (or prevent it from starting in the first place for security / procedural reasons) we don't want the client wasting 30 minutes finishing the stream before receiving the FaultException from the server.

    Take the following (simplified WCF service):

    Namespace JP_WCF <ServiceContract> _ Public Interface IJP_WCF <OperationContract> _ <FaultContract(GetType(JP_WCF_Fault))> _ Sub UploadFile(request As JP_WCF_FileUpload) <OperationContract> _ <FaultContract(GetType(JP_WCF_Fault))> _ Function fakeError(ByVal int1 As Integer, ByVal int2 As Integer) As Integer <OperationContract> _ <FaultContract(GetType(JP_WCF_Fault))> _ Function Ping() As Date End Interface <MessageContract> _ Public Class JP_WCF_FileUpload Implements IDisposable <MessageHeader(MustUnderstand:=True)> _ Public FileName As String <MessageHeader(MustUnderstand:=True)> _ Public Length As Long <MessageBodyMember(Order:=1)> _ Public FileByteStream As System.IO.Stream Public Sub Dispose() Implements IDisposable.Dispose If FileByteStream IsNot Nothing Then FileByteStream.Close() FileByteStream = Nothing End If End Sub End Class <DataContract> _ Public Class JP_WCF_Fault <DataMember> _ Public Property EventID() As Integer <DataMember> _ Public Property Message() As String <DataMember> _ Public Property Description() As String Public Sub New(ByVal _EventID As Integer, ByVal _Message As String, ByVal _Description As String) Me.EventID = _EventID Me.Message = _Message Me.Description = _Description End Sub End Class End Namespace

    Server Method:

    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

    Client Method:

    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()

    web.config (Server):

    <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>

    app.config (client)

     <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>

    I'm pretty new to WCF so any help would be greatfully appreciated.

    Regards

    Jordon


    HeavenCore IT Solutions

    Thursday, October 5, 2017 10:21 AM

All replies

  • Hi Jordon,

    In my option, we could not abort client request from Service side.

    Based on your current code, before the request received at Service side, your stream process will be finished.

    Where will throw the FaultException? It seems it will throw while writing stream to file. To check when will the Service receive the request, I suggest you set a breakpoint at Service Method and Client UploadFile request.

    For a possible way, I would suggest you split your client file into multiple block, which means you send the file block by block, and then at service side, check whether the file upload has been finished, if not, append the stream to the unfinished file.

    Best Regards,

    Edward


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Friday, October 6, 2017 5:31 AM