Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/335.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 让IIS托管的WCF服务中的流媒体正常工作_C#_Wcf_Iis_Azure - Fatal编程技术网

C# 让IIS托管的WCF服务中的流媒体正常工作

C# 让IIS托管的WCF服务中的流媒体正常工作,c#,wcf,iis,azure,C#,Wcf,Iis,Azure,我被困在这里了 我的目标很简单:我想公开一个由IIS托管(然后是Windows Azure)的WCF服务,通过该服务,我可以使用流媒体上传文件,并添加一些有关我要上传的文件的元数据(文件名、MD5哈希所有常用内容…),并能够显示有关上传的准确进度信息 首先,我创建了一个派生类StreamWithProgress,它继承自FileStream,在这里我重写了Read方法,以在每次读取时引发一个事件,并传递进度信息 其次,我创建了一个WCF服务,使用MessageContract()将元数据和流对象

我被困在这里了

我的目标很简单:我想公开一个由IIS托管(然后是Windows Azure)的WCF服务,通过该服务,我可以使用流媒体上传文件,并添加一些有关我要上传的文件的元数据(文件名、MD5哈希所有常用内容…),并能够显示有关上传的准确进度信息

首先,我创建了一个派生类StreamWithProgress,它继承自FileStream,在这里我重写了Read方法,以在每次读取时引发一个事件,并传递进度信息

其次,我创建了一个WCF服务,使用MessageContract()将元数据和流对象包装到单个SOAP信封中。这个服务非常简单,只公开一个上传方法

我已将所有缓冲区大小设置为接受大量数据,如下所示:

以及httpRuntime设置,如下所示:

IIS\ASP兼容性设置如下所示:

并根据以下要求禁用批处理:

我已经创建了一个自托管服务,通过该服务上传成功。 然后我将它“升级”到一个IIS托管服务(在我的本地机器上),它运行正常。 然后,我创建了一个本地托管的windowsazure服务,其中有一个wcfwebrole,,可以正常工作

但问题是,在所有实例中都没有发生实际的流式传输……所有实例都在发送数据之前缓冲了数据

当我看到我的客户机正在报告进度时,我遇到了这个问题,但是服务器直到整个文件被缓冲后才开始写入文件

我的实际代码如下

有什么想法/帮助吗? 任何事情都将不胜感激

谢谢

服务器web.config:

<?xml version="1.0"?>
<configuration>
    <system.serviceModel>

        <bindings>
            <basicHttpBinding>
                <binding name="uploadBasicHttpBinding" 
                 maxReceivedMessageSize="2147483647" 
                 transferMode="Streamed" 
                 messageEncoding="Mtom"
                 maxBufferPoolSize="2147483647"
                 maxBufferSize="2147483647">
                 <readerQuotas maxArrayLength="2147483647" 
                                maxBytesPerRead="2147483647" 
                                maxDepth="2147483647" 
                                maxNameTableCharCount="2147483647" 
                                maxStringContentLength="2147483647"/>
                </binding>
            </basicHttpBinding>
        </bindings>

            <behaviors>
                <serviceBehaviors>
                    <behavior name="defaultBehavior">
                        <serviceMetadata httpGetEnabled="true"/>
                        <serviceDebug includeExceptionDetailInFaults="false"/>
                        <dataContractSerializer maxItemsInObjectGraph="2147483647"/>
                    </behavior>
                </serviceBehaviors>
            </behaviors>

        <!-- Add this for BufferOutput setting -->
        <serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true"/>

        <services>
            <service name="WcfService1.Service1" behaviorConfiguration="defaultBehavior">           
                <endpoint binding="basicHttpBinding" contract="WcfService1.IService1" bindingConfiguration="uploadBasicHttpBinding"/>
                <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
            </service>
        </services>

    </system.serviceModel>

    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true"/>
    </system.webServer>

    <system.web>
        <compilation debug="true"/>
    <httpRuntime maxRequestLength="2147483647" />
    </system.web>

</configuration>
实际服务:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

using System.IO;
using System.Web;
using System.ServiceModel.Activation;

namespace WcfService1
{
    [MessageContract]
    public class Encapsulator
    {
        [MessageHeader(MustUnderstand = true)]
        public string fileName;
        [MessageBodyMember(Order = 1)]
        public Stream requestStream;
    }

    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class Service1 : IService1
    {
        public Service1()
        {
            HttpContext context = HttpContext.Current;

            if (context != null)
            {
                context.Response.BufferOutput = false;
            }
        }

        public void UploadStream(Encapsulator data)
        {
            const int BUFFER_SIZE = 1024;

            int bytesRead = 0;

            byte[] dataRead = new byte[BUFFER_SIZE];

            string filePath = Path.Combine(@"C:\MiscTestFolder", data.fileName);

            string logPath = Path.Combine(@"C:\MiscTestFolder", string.Concat(data.fileName, ".log"));

            bytesRead = data.requestStream.Read(dataRead, 0, BUFFER_SIZE);

            StreamWriter logStreamWriter = new StreamWriter(logPath);

            using (System.IO.FileStream fileStream = new System.IO.FileStream(filePath, FileMode.Create))
            {
                while (bytesRead > 0)
                {
                    fileStream.Write(dataRead, 0, bytesRead);
                    fileStream.Flush();

                    logStreamWriter.WriteLine("Flushed {0} bytes", bytesRead.ToString());
                    logStreamWriter.Flush();

                    bytesRead = data.requestStream.Read(dataRead, 0, BUFFER_SIZE);
                }

                fileStream.Close();
            }

            logStreamWriter.Close();
        }
    }
}
客户端app.config:

<?xml version="1.0"?>
<configuration>
    <system.serviceModel>

        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_IService1" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
                    maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                    messageEncoding="Mtom" textEncoding="utf-8" transferMode="Streamed"
                    useDefaultWebProxy="true">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <security mode="None">
                        <transport clientCredentialType="None" proxyCredentialType="None"
                            realm="" />
                        <message clientCredentialType="UserName" algorithmSuite="Default" />
                    </security>
                </binding>
            </basicHttpBinding>
        </bindings>

        <client>
            <endpoint address="http://localhost/WcfService1/Service1.svc"
                binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService1"
                contract="UploadService.IService1" name="BasicHttpBinding_IService1" />
        </client>

    </system.serviceModel>

    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
    </startup>
</configuration>

客户端主代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using CustomFileUploaderTester.UploadService;
using System.ServiceModel;
using System.IO;

namespace CustomFileUploaderTester
{
    class Program
    {
        private static long bytesRead = 0;

        static void Main(string[] args)
        {
            Service1Client client = new Service1Client();

            using (StreamWithProgress fstream = new StreamWithProgress(@"C:\BladieBla\someFile.wmv", FileMode.Open))
            {
                client.InnerChannel.AllowOutputBatching = false;

                fstream.ProgressChange += new EventHandler<StreamReadProgress>(fstream_ProgressChange);

                client.UploadStream("someFile.wmv", fstream);

                fstream.Close();
            }

            Console.ReadKey();
        }

        static void fstream_ProgressChange(object sender, StreamReadProgress e)
        {
            bytesRead += e.BytesRead;

            Console.WriteLine(bytesRead.ToString());
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用CustomFileUploaderTester.UploadService;
使用System.ServiceModel;
使用System.IO;
命名空间CustomFileUploaderTester
{
班级计划
{
私有静态长字节读=0;
静态void Main(字符串[]参数)
{
Service1Client客户端=新的Service1Client();
使用(StreamWithProgress fstream=newstreamwithprogress(@“C:\BladieBla\someFile.wmv”,FileMode.Open))
{
client.InnerChannel.AllowOutBatching=false;
fstream.ProgressChange+=新事件处理程序(fstream\u ProgressChange);
UploadStream(“someFile.wmv”,fstream);
fstream.Close();
}
Console.ReadKey();
}
静态void fstream\u ProgressChange(对象发送方,StreamReadProgress e)
{
字节读取+=e.字节读取;
Console.WriteLine(bytesRead.ToString());
}
}
}
派生的文件流类(StreamWithProgress

使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.IO;
命名空间CustomFileUploaderTester
{
公共类StreamReadProgress:EventArgs
{
#区域公共财产
公共长字节阅读
{
得到;
设置
}
公共长线
{
得到;
设置
}
#端区
#区域构造函数
公共StreamReadProgress(长字节读取、长文件长度)
:base()
{
this.BytesRead=BytesRead;
this.Length=文件长度;
}
#端区
}
公共密封类StreamWithProgress:FileStream
{
#区域公共活动
公共事件事件处理程序变更;
#端区
#区域构造函数
公共流WithProgress(字符串文件路径、文件模式文件模式)
:base(文件路径、文件模式)
{
}
#端区
#区域覆盖
公共重写整型读取(字节[]数组、整型偏移量、整型计数)
{
int bytesRead=base.Read(数组、偏移量、计数);
此.RaiseProgressChanged(bytesRead);
返回字节读取;
}
#端区
#区域私人工作者方法
私有void RaiseProgressChanged(长字节读取)
{
EventHandler progressChange=this.progressChange;
if(progressChange!=null)
{
progressChange(this,newstreamreadprogress(bytesRead,this.Length));
}
}
#端区
}
}
--更新:2012-04-20

在安装了环回适配器之后,我使用RawCap跟踪了通信,发现数据实际上是流式传输的,但是IIS服务器在调用web方法之前正在缓冲所有数据

根据这篇文章:

WCF继承的是ASP.Net行为。。。但他们在谈论.Net 4.5中的修复:|

如果有人有任何其他的建议,这将是伟大的


谢谢

您正在将Mtom与流式传输模式一起使用。这可能会引起一些问题。请尝试删除Mtom。实际上,Mtom是一个非常古老的标准。此外,当使用具有流传输模式的SOAP服务时,我们只能有一个类型为Stream的参数。我们不能使用像封装器这样的自定义类型

构建文件u的建议解决方案
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using CustomFileUploaderTester.UploadService;
using System.ServiceModel;
using System.IO;

namespace CustomFileUploaderTester
{
    class Program
    {
        private static long bytesRead = 0;

        static void Main(string[] args)
        {
            Service1Client client = new Service1Client();

            using (StreamWithProgress fstream = new StreamWithProgress(@"C:\BladieBla\someFile.wmv", FileMode.Open))
            {
                client.InnerChannel.AllowOutputBatching = false;

                fstream.ProgressChange += new EventHandler<StreamReadProgress>(fstream_ProgressChange);

                client.UploadStream("someFile.wmv", fstream);

                fstream.Close();
            }

            Console.ReadKey();
        }

        static void fstream_ProgressChange(object sender, StreamReadProgress e)
        {
            bytesRead += e.BytesRead;

            Console.WriteLine(bytesRead.ToString());
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace CustomFileUploaderTester
{
    public class StreamReadProgress : EventArgs
    {
        #region Public Properties

        public long BytesRead
        {
            get;
            set;
        }

        public long Length
        {
            get;
            set;
        }

        #endregion

        #region Constructor

        public StreamReadProgress(long bytesRead, long fileLength)
            : base()
        {
            this.BytesRead = bytesRead;

            this.Length = fileLength;
        }

        #endregion
    }

    public sealed class StreamWithProgress : FileStream
    {
        #region Public Events

        public event EventHandler<StreamReadProgress> ProgressChange;

        #endregion

        #region Constructor

        public StreamWithProgress(string filePath, FileMode fileMode)
            : base(filePath, fileMode)
        {
        }

        #endregion

        #region Overrides

        public override int Read(byte[] array, int offset, int count)
        {
            int bytesRead = base.Read(array, offset, count);

            this.RaiseProgressChanged(bytesRead);

            return bytesRead;
        }

        #endregion

        #region Private Worker Methods

        private void RaiseProgressChanged(long bytesRead)
        {
            EventHandler<StreamReadProgress> progressChange = this.ProgressChange;

            if (progressChange != null)
            {
                progressChange(this, new StreamReadProgress(bytesRead, this.Length));
            }
        }


        #endregion
    }
}