我们有一个WCF服务,它接受来自客户端的流(客户端将文件上传到服务器).但是,如果服务器在流之前或期间抛出FaultException,则客户端只会继续流式传输直到结束,此时它会从服务器接收FaultException - 浪费时间和带宽为客户端.
类似问题:
采取以下(简化的WCF服务)
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
Run Code Online (Sandbox Code Playgroud)
示例服务器方法:
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
Run Code Online (Sandbox Code Playgroud)
示例客户端方法:
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()
Run Code Online (Sandbox Code Playgroud)
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>
Run Code Online (Sandbox Code Playgroud)
的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>
Run Code Online (Sandbox Code Playgroud)
您的客户有双工通道吗?如果是这样,那么在上传文件时回调客户端合约以发送信息就非常简单了。
如果没有,那么一种好的方法是使用内存缓冲区将数据分块流式传输到服务器。我在下面列出了一些很好的例子。
要点是,您在客户端上将文件分割成块,然后将其逐块发送到服务器。如果任何块失败,那么它可以重试该块,或者优雅地失败而不发送任何更多数据。
这些引用利用一个StreamWithProgress类来处理客户端上的此逻辑。希望这可以帮助。
| 归档时间: |
|
| 查看次数: |
205 次 |
| 最近记录: |