2017-06-14 6 views
0

Ich arbeite gerade an einem WCF-Streamingdienst. Bis jetzt funktioniert alles super für Dateien bis 2 GB. Ich habe den Dienst als Streamingdienst eingerichtet und chunke die Dateien selbst auf 5-MB-Chunks. Allerdings, Dateien größer als 2 GB (irgendwo gibt es die Schwelle) ich bekomme immer eine InvalidOperationException mit der Nachricht Timeouts are not supported on this stream. Ich bin nicht wirklich sicher, warum und wo diese Ausnahme ausgelöst wird. Sie denken nicht, dass dies ein serverseitiges Problem ist, da jede Anfrage die gleiche sein sollte und die meisten von ihnen funktionieren. Die Ausnahmen stammen jedoch vom generierten Proxy. So ist die Quelle System.Private.ServiceModelWCF-Timeout-Ausnahme beim Streamen großer Dateien

Stapelüberwachung:

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

Hier ist mein Server 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; 
         } 
        } 
       } 

Die GetFileResponse sieht wie folgt aus:

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

Dies ist, wie der Client handhabt den Download (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(); 
        } 
       } 

Und hier ist der Service 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> 

Wenn die Client-Proxy-Generierung, i gesetzt einige Timeouts, aber das alles hat sich nicht geändert:

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

Jede Idee, wo und warum die Ausnahme ausgelöst wird? Server? Klient? Kommt es aus dem Strom? Hilfe wird sehr geschätzt.

+0

Gibt es eine Möglichkeit, dies zu pushen? :) Für den Fall, dass es verloren geht - ich bin immer noch mit dem Fehler konfrontiert und würde mich über Hilfe freuen. – Megalomaniac

Antwort

0

Für alle anderen, die das gleiche Problem haben. Ich habe es gelöst, indem ich die Ausnahmen mit der WCF TraceViewer analysiere. Ich habe auch den Service von einer Konsolenanwendung aus aufgerufen, um sicher zu sein, dass es kein UWP-Problem ist. Das Problem war, dass ich die Streams schloss, bevor die Antwort den Client erreichen konnte.

Gebrochene Umsetzung:

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

Dieses es für mich festgelegt:

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; 

Hoffe, es hilft!

Verwandte Themen