2017-06-14 50 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; 

希望它能帮助!