2017-06-14 91 views
0

我目前正在使用WCF流服務。到目前爲止,對於文件高達2 GB,一切都很好。我已經將該服務設置爲流媒體服務,並且我以5 MB塊自行分割文件。但是,大於2 GB的文件(某處存在閾值),我總是得到一個InvalidOperationException,並顯示消息Timeouts are not supported on this stream.我不確定爲什麼以及在何處引發此異常。它不認爲這是一個服務器端問題,因爲每個請求應該是相同的,其中大多數的工作。但例外來自生成的代理。所以源是System.Private.ServiceModel流大文件WCF超時異常

堆棧跟蹤:

at System.Runtime.AsyncResult.End[TAsyncResult](IAsyncResult result) 
    at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.End(SendAsyncResult result) 
    at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result) 
    at System.ServiceModel.Channels.ServiceChannelProxy.TaskCreator.<>c__DisplayClass0.<CreateGenericTask>b__1(IAsyncResult asyncResult) 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() 
    at Company.OurApp.App.DataService.BaseFile.<DownloadItem>d__59.MoveNext() 

這裏是我的服務器implementaion:

var response = new GetFileResponse(); 
       using (var impersonation = new Impersonation(request.Domain, request.Username, request.Password)) 
       { 
        using (Stream fStream = File.OpenRead(request.FullFilePath)) 
        { 
         fStream.Seek(request.FilePart * request.FilePartSize, SeekOrigin.Begin); 
         BinaryReader bStream = new BinaryReader(fStream); 
         var filePart = bStream.ReadBytes(request.FilePartSize); 

         using (Stream mStream = new MemoryStream(filePart)) 
         { 
          response.FileByteStream = mStream; 
          return response; 
         } 
        } 
       } 

的GetFileResponse看起來是這樣的:

[MessageContract] 
public class GetFileResponse 
{ 
    [MessageBodyMember(Order = 1)] 
    public Stream FileByteStream { get; set; } 
} 

這是怎樣的客戶端處理下載(UWP App):

using (Stream f = await StorageFile.OpenStreamForWriteAsync()) 
       { 
        //Cancelation area - after every async operation if possilble 
        for (int i = 0; i < sections; i++) 
        { 
         token.ThrowIfCancellationRequested(); 
         var response = await client.GetFilePartAsync(request.ConnectionPassword, request.Domain, i, FilePartSize, FullPath, request.Password, request.Username); 
         token.ThrowIfCancellationRequested(); 
         DownloadProgress = response.FileByteStream.Length; 

         f.Seek(0, SeekOrigin.End); 
         await f.WriteAsync(response.FileByteStream, 0, response.FileByteStream.Length); 
         await f.FlushAsync(); 
        } 
       } 

這裏是服務的web.config:

<system.serviceModel> 
    <services> 
     <service behaviorConfiguration="HttpsServiceBehaviour" 
       name="Company.OurApp.TransportService.DataService"> 
     <endpoint address="" binding="basicHttpBinding" bindingConfiguration="streamedBinding" contract="Company.OurAppTransportService.IDataService"> 
     </endpoint> 
     </service> 
    </services> 
    <behaviors> 
     <serviceBehaviors> 
     <behavior name="HttpsServiceBehaviour"> 
      <!-- To avoid disclosing metadata information, set the values below to false before deployment --> 
      <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/> 
      <!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information --> 
      <serviceDebug includeExceptionDetailInFaults="true"/> 
     </behavior> 
     </serviceBehaviors> 
    </behaviors> 
    <bindings> 
     <basicHttpBinding> 
     <binding name="streamedBinding" transferMode="Streamed" closeTimeout="10:00:00"> 
      <security mode="TransportCredentialOnly"> 
      <transport clientCredentialType="Windows" /> 
      </security> 
     </binding> 
     </basicHttpBinding> 
    </bindings> 

當生成客戶端代理,我設置一些超時但這並沒有改變什麼:

public DataServiceClient GetDataServiceClient(string endpoint = null) 
     { 
      var useEndpoint = String.IsNullOrEmpty(endpoint) ? Configuration.ConfigService : endpoint; 

      System.ServiceModel.BasicHttpBinding result = new System.ServiceModel.BasicHttpBinding(); 
      result.MaxBufferSize = int.MaxValue; 
      result.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max; 
      result.MaxReceivedMessageSize = int.MaxValue; 
      result.AllowCookies = true; 
      result.Security.Transport.ClientCredentialType = System.ServiceModel.HttpClientCredentialType.Windows; 

      //TODO Try to work with timeouts for larges files? 
      result.SendTimeout = TimeSpan.FromMinutes(5); 
      result.ReceiveTimeout = TimeSpan.FromMinutes(5); 
      result.OpenTimeout = TimeSpan.MaxValue; 


      if (useEndpoint.ToLower().StartsWith("https://")) 
       result.Security.Mode = System.ServiceModel.BasicHttpSecurityMode.Transport; 
      else 
       result.Security.Mode = System.ServiceModel.BasicHttpSecurityMode.TransportCredentialOnly; 

      var client = new DataServiceClient(result, new System.ServiceModel.EndpointAddress(String.Concat(useEndpoint, fixedEndpointSuffix))); 
      client.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation; 

      if (AppState.IsLoggedIn) 
      { 
       client.ClientCredentials.Windows.ClientCredential.UserName = [email protected]"{AppState.Domain}\{AppState.User}"; 
       client.ClientCredentials.Windows.ClientCredential.Password = AppState.Password; 
      } 

      return client; 
     } 

任何想法,以及爲什麼拋出異常?服務器?客戶?它來自流?非常感謝幫助。

+0

有沒有辦法推這個? :)以防萬一它丟失了 - 我仍然面臨着錯誤,並會感謝一些幫助。 – Megalomaniac

回答

0

對於其他人面臨同樣的問題。我通過分析WCF TraceViewer的例外來解決問題。我還從控制檯應用程序中調用該服務以確保它不是UWP問題。問題是我在響應可能到達客戶端之前關閉了流。

破碎執行:

var response = new GetFileResponse(); 
      using (var impersonation = new Impersonation(request.Domain, request.Username, request.Password)) 
      { 
       using (Stream fStream = File.OpenRead(request.FullFilePath)) 
       { 
        fStream.Seek(request.FilePart * request.FilePartSize, SeekOrigin.Begin); 
        BinaryReader bStream = new BinaryReader(fStream); 
        var filePart = bStream.ReadBytes(request.FilePartSize); 

        using (Stream mStream = new MemoryStream(filePart)) 
        { 
         response.FileByteStream = mStream; 
         return response; 
        } 
       } 
      } 

這一個固定對我來說:

Stream fStream = File.OpenRead(request.FullFilePath); 

       long offset = request.FilePart * request.FilePartSize; 
       fStream.Seek(offset, SeekOrigin.Begin); 

       BinaryReader bStream = new BinaryReader(fStream); 
       var filePart = bStream.ReadBytes((int)request.FilePartSize); 

       Stream mStream = new MemoryStream(filePart); 

       response.FileByteStream = mStream; 
       return response; 

希望它能幫助!