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.
Similar Question:
How to Abort a WCF File Upload from the Server-Side Method
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
Example 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
Example 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
<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
<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>
1 Answers
Answers 1
If you're concerned about the performance of this call, you could always make a server call to check the validity of this upload prior to streaming it. That way you can avoid streaming the file at all if there's a problem and avoid any exception state in your application (also expensive).
So you would make relatively quick trip to the server to validate things like
- valid file location
- permission to write to that location
- the size of the file being valid
- any relevant business rules
Then you can make your call without trying to manage application flow using exceptions. Remember: Exceptions should be for exceptional circumstances. This way if your application does raise an exception, it means that something very abnormal has happened and a dip in speed is more palatable (since this case would be theoretically very rare).
0 comments:
Post a Comment