获取在IIS托管流WCF服务工作 [英] Getting Streaming in IIS Hosted WCF service to work

查看:238
本文介绍了获取在IIS托管流WCF服务工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有点坚持在这里...

I'm kinda stuck here...

我的目标很简单:我要揭露一个IIS托管(然后Windows Azure中)WCF服务,通过它我可以上传文件,使用流媒体,并添加有关我要上传的文件(文件名,MD5一些元数据-hash所有平常的东西......),并能够显示关于上传进度准确的信息。

My goal is quite simple: I want to expose an IIS hosted (and then Windows Azure) WCF service through which I can upload files, using streaming, and add some META data about the file I want to upload (filename, MD5-hash all the usual stuff...), and to be able to display accurate progress information regarding the upload.

所有我创建了一个派生类的第一 StreamWithProgress 从继承的的FileStream ,在那里我已经覆盖了法引发一个事件每次读通过我传递的进展情况。

First of all I created a derived class StreamWithProgress which inherits from FileStream, where I have overridden the Read method to raise an event with each read through which I pass progress information.

其次我使用创造了一个WCF服务的 MessageContract (适用的 http://msdn.microsoft.com/en-us/library/ms730255.aspx )来包装的META数据,以及流对象到一个单一的SOAP信封。这项服务是非常简单,只露出上传一个方法。

Secondly I created a WCF service using a MessageContract ( http://msdn.microsoft.com/en-us/library/ms730255.aspx ) to wrap the META data, and the stream object into a single SOAP envelope. This service is really simple, exposing only a single method for upload.

我已经设置所有的缓冲区大小,接受大量的数据,按:

I have set all the buffer sizes to accept large amounts of data, as per:

http://msdn.microsoft.com/ EN-US /库/ ms733742.aspx

http://msdn.microsoft.com/ EN-US /库/ ms731325.aspx

和的httpRuntime设置,按

and the httpRuntime settings as per:

http://kjellsj.blogspot.com/2007/02/wcf-streaming-upload-files-over-http.html

在IIS \\ ASP兼容性设置按:

the IIS\ASP Compatibility settings as per:

WCF流媒体文件传输基于.NET 4

和禁用配料按:

我创建了一个自助托管服务,通过它上传成功。
然后,我升级它的 IIS托管服务(我的本地计算机上),它的工作。
然后,我创建了一个本地托管的Windows Azure服务,与WCF webrole,哪些工作。

I have created a self hosted service through which the upload succeeded. Then I ‘upgraded’ it to an IIS hosted service (on my local machine), which worked. Then I created a locally hosted Windows Azure service, with a WCF webrole, which worked.

美中不足的是,虽然在没有实例并实际流发生......所有这些发送之前缓冲的数据。

The catch though is that in none of the instances did actual streaming take place… All of them buffered the data before sending it.

我碰到这个问题,当我看到我的客户是报告进展,但服务器不会启动写入文件,直到整个文件缓冲之后。

I came across this problem, when I saw that my client is reporting progress, but the server doesn’t start writing the file until after the entire file was buffered.

我的实际code如下:

My actual code follows.

任何意见\\帮助吗?
任何将大大AP preciated ...

Any ideas\help? Anything will be greatly appreciated…

谢谢!

服务器的web.config:

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

namespace WcfService1
{
    [ServiceContract]
    public interface IService1
    {
        [OperationContract(IsOneWay=true)]
        void UploadStream(Encapsulator data);
    }
}

实际的服务:

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:

Client 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>

客户端主要code:

Client Main code:

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

派生FileStream类( StreamWithProgress

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

- 更新:2012-04-20

我已经安装了环回适配器之后,我跟踪通讯科与RawCap,看到这些数据实际上是串流播放,但在IIS服务器调用Web方法之前缓冲所有数据!

After I have installed a loop-back adapter, I traced the comms with RawCap, and saw that the data is actually streamed, but that the IIS server is buffering all the data before invoking the web method!

根据这个帖子:

http://social.msdn.microsoft.com/Forums/is/wcf/thread/cfe625b2-1890-471b-a4bd-94373daedd39

它是WCF继承ASP.Net的行为......但是,他们在谈论.NET 4.5修复此:|

it's ASP.Net behavior that WCF inherits... But they're talking about fixes for this in .Net 4.5 :|

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

If anyone has any other suggestion it will be great!

谢谢!

推荐答案

一些严格的测试后,我看到的数据实际上是被流。我应用了 [MessageContract] 属性的封装器类
(按照 http://msdn.microsoft.com/en-us/library/ ms733742.aspx ),这使我能够发送有关文件的一些额外的元数据。运用
Wireshark主RawCap是很清楚,数据通过网络发送,而流被读取。

After some rigorous testing, I saw that data is actually being streamed. I applied the [MessageContract] attribute to the Encapsulator class (as per http://msdn.microsoft.com/en-us/library/ms733742.aspx), and that enabled me to send some extra Meta data about the file. Using WireShark and RawCap is was clear that data was sent over the wire while the Stream was read.

这探出头来,是缓冲服务器端(使用IIS 7.5)实际上是调用上传方法之前被流中的数据的另一个问题!
这是一个有点担心,但根据本:的http://social.msdn.microsoft.com/Forums/is/wcf/thread/cfe625b2-1890-471b-a4bd-94373daedd39,
修复应该是在.net的4.5版本

The other problem that stuck his head out, was that the data being streamed is buffered server-side (using IIS 7.5) before the upload method is actually invoked! This is a bit of a concern, but according to this: http://social.msdn.microsoft.com/Forums/is/wcf/thread/cfe625b2-1890-471b-a4bd-94373daedd39, a fix should be in the 4.5 release of .Net

这篇关于获取在IIS托管流WCF服务工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆