流媒体大文件上的WCF超时异常

时间:2017-06-14 10:23:25

标签: wcf uwp streaming

我目前正在开发WCF流媒体服务。到目前为止,一切都适用于高达2 GB的文件。我已将该服务设置为流服务,并且我将自己的文件分块为5 MB块。但是,大于2 GB的文件(某处有阈值)我总是得到InvalidOperationException消息Timeouts are not supported on this stream.我不确定为什么以及抛出此异常的原因。它不认为这是服务器方面的问题,因为每个请求应该是相同的,并且大多数都是有效的。但例外来自生成的代理。所以来源是System.Private.ServiceModel

堆栈追踪:

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

这是我的服务器实现:

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 = $@"{AppState.Domain}\{AppState.User}";
                client.ClientCredentials.Windows.ClientCredential.Password = AppState.Password;
            }

            return client;
        }

知道抛出异常的地点和原因吗?服务器?客户?它来自溪流吗?非常感谢帮助。

1 个答案:

答案 0 :(得分: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;

希望它有所帮助!