我有點困在這裏...獲取流媒體在IIS託管WCF服務工作
我的目標很簡單:我要揭露一個IIS託管(然後Windows Azure中)WCF服務,通過它我可以上傳文件,使用流媒體,以及添加一些關於我想要上傳的文件的META數據(文件名,MD5-hash所有常用的東西......),並能夠顯示有關上傳的準確進度信息。
首先我創建了一個派生類StreamWithProgress從的FileStream,其中我已經覆蓋了讀方法引發一個事件與每個讀通過我通過進度信息繼承。
其次我創建使用MessageContract(http://msdn.microsoft.com/en-us/library/ms730255.aspx)來包裝元數據的WCF服務和流對象到一個單一的SOAP信封。這項服務非常簡單,僅提供一種上傳方法。
我已經將所有的緩衝區大小,以接受大量的數據,按:
和的httpRuntime設置爲每:
http://msdn.microsoft.com/en-us/library/e1f13641(v=vs.71).aspx和
http://kjellsj.blogspot.com/2007/02/wcf-streaming-upload-files-over-http.html
的IIS \ ASP兼容性設置按:
和禁用配料按:
- http://msdn.microsoft.com/en-us/library/system.servicemodel.icontextchannel.allowoutputbatching.aspx
我創建了一個自託管服務通過它上傳成功。 然後我'升級'到IIS託管服務(在我的本地計算機上),它工作。 然後我創建了一個本地託管的Windows Azure服務,其中有一個工作的WCF卷軸,。
儘管如此,沒有一個實例發生實際流式傳輸......所有這些實例都在發送數據之前對其進行了緩衝。
我遇到了這個問題,當我看到我的客戶端正在報告進度,但服務器在整個文件被緩衝之後纔開始寫入文件。
我的實際代碼如下。
任何想法\幫助? 任何將不勝感激...
謝謝!
服務器的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:
<?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());
}
}
}
派生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服務器在調用之前緩存所有數據網絡方法!
根據這個帖子:
http://social.msdn.microsoft.com/Forums/is/wcf/thread/cfe625b2-1890-471b-a4bd-94373daedd39
它是WCF繼承ASP.Net行爲......但是,他們在.NET 4.5談論修復此:|
如果有人有任何其他建議,它將是偉大的!
謝謝!
如果您降低服務器端MaxBufferSize屬性,它會產生什麼影響嗎? – RichBower 2012-04-19 15:23:51
嗨RichBower,我試過,謝謝...在你的帖子後,我去了所有的ReaderQuota和綁定設置...但無濟於事...... – mnemonic 2012-04-20 07:14:51