使用WCF上传文件
? 在WCF沒出現(xiàn)之前,我一直使用用WebService來上傳文件,我不知道別人為什么要這么做,因為我們的文件服務器和網(wǎng)站后臺和網(wǎng)站前臺都不在同一個機器,操作人員覺得用FTP傳文件太麻煩,我就做一個專門用來上傳文件的WebService,把這個WebService部署在文件服務器上,然后在網(wǎng)站后臺調(diào)用這個WebService,把網(wǎng)站后臺頁面上傳上來的文件轉(zhuǎn)化為字節(jié)流傳給WebService,然后WebService把這個字節(jié)流保存文件到一個只允許靜態(tài)頁面的網(wǎng)站(靜態(tài)網(wǎng)站可以防止一些腳本木馬)。
WebService來上傳文件存在的問題是效率不高,而且不能傳輸大數(shù)據(jù)量的文件,當然你可以用Wse中的MTOM來傳輸大文件,有了WCF就好多了,通過使用WCF傳遞Stream對象來傳遞大數(shù)據(jù)文件,但有一些限制:
????public?interface?IUpLoadService
????{
????????[OperationContract(Action?=?"UploadFile",?IsOneWay?=?true)]
????????void?UploadFile(FileUploadMessage?request);
????}
????[MessageContract]
????public?class?FileUploadMessage
????{
????????[MessageHeader(MustUnderstand?=?true)]
????????public?string?SavePath;
????????[MessageHeader(MustUnderstand?=?true)]
????????public?string?FileName;
????????[MessageBodyMember(Order?=?1)]
????????public?Stream?FileData;
????}
????{
????????public?void?UploadFile(FileUploadMessage?request)
????????{
????????????string?uploadFolder?=?@"C:\kkk\";
????????????string?savaPath?=?request.SavePath;
????????????string?dateString?=?DateTime.Now.ToShortDateString()?+?@"\";
????????????string?fileName?=?request.FileName;
????????????Stream?sourceStream?=?request.FileData;
????????????FileStream?targetStream?=?null;
???????????
????????????if?(!sourceStream.CanRead)
????????????{
????????????????throw?new?Exception("數(shù)據(jù)流不可讀!");
????????????}
????????????if?(savaPath?==?null)?savaPath?=?@"Photo\";
????????????if?(!savaPath.EndsWith("\\"))?savaPath?+=?"\\";
????????????uploadFolder?=?uploadFolder?+?savaPath?+?dateString;
????????????if?(!Directory.Exists(uploadFolder))
????????????{
????????????????Directory.CreateDirectory(uploadFolder);
????????????}
????????????string?filePath?=?Path.Combine(uploadFolder,?fileName);
????????????using?(targetStream?=?new?FileStream(filePath,?FileMode.Create,?FileAccess.Write,?FileShare.None))
????????????{
????????????????//read?from?the?input?stream?in?4K?chunks
????????????????//and?save?to?output?stream
????????????????const?int?bufferLen?=?4096;
????????????????byte[]?buffer?=?new?byte[bufferLen];
????????????????int?count?=?0;
????????????????while?((count?=?sourceStream.Read(buffer,?0,?bufferLen))?>?0)
????????????????{
????????????????????targetStream.Write(buffer,?0,?count);
????????????????}
????????????????targetStream.Close();
????????????????sourceStream.Close();
????????????}
????????}
????}
????<bindings>
??????<basicHttpBinding>
????????<binding?name="FileTransferServicesBinding"?maxReceivedMessageSize="9223372036854775807"
??????????messageEncoding="Mtom"?transferMode="Streamed"?sendTimeout="00:10:00"?/>
??????????</basicHttpBinding>
????</bindings>
????<services>
??????<service?behaviorConfiguration="UploadWcfService.UpLoadServiceBehavior"
????????name="UploadWcfService.UpLoadService">
????????<endpoint?address=""?binding="basicHttpBinding"?bindingConfiguration="FileTransferServicesBinding"?contract="UploadWcfService.IUpLoadService">
????????</endpoint>
????????<endpoint?address="mex"?binding="mexHttpBinding"?contract="IMetadataExchange"?/>
??????</service>
????</services>
????<behaviors>
??????<serviceBehaviors>
????????<behavior?name="UploadWcfService.UpLoadServiceBehavior">
??????????<serviceMetadata?httpGetEnabled="true"?/>
??????????<serviceDebug?includeExceptionDetailInFaults="false"?/>
????????</behavior>
??????</serviceBehaviors>
????</behaviors>
??</system.serviceModel>
WebService來上傳文件存在的問題是效率不高,而且不能傳輸大數(shù)據(jù)量的文件,當然你可以用Wse中的MTOM來傳輸大文件,有了WCF就好多了,通過使用WCF傳遞Stream對象來傳遞大數(shù)據(jù)文件,但有一些限制:
1、只有 BasicHttpBinding、NetTcpBinding 和 NetNamedPipeBinding 支持傳送流數(shù)據(jù)。
2、 流數(shù)據(jù)類型必須是可序列化的 Stream 或 MemoryStream。
3、 傳遞時消息體(Message Body)中不能包含其他數(shù)據(jù)。
4、TransferMode的限制和MaxReceivedMessageSize的限制等。
下面具體實現(xiàn):新建一個WCFService,接口文件的代碼如下:
[ServiceContract]
????public?interface?IUpLoadService
????{
????????[OperationContract(Action?=?"UploadFile",?IsOneWay?=?true)]
????????void?UploadFile(FileUploadMessage?request);
????}
????[MessageContract]
????public?class?FileUploadMessage
????{
????????[MessageHeader(MustUnderstand?=?true)]
????????public?string?SavePath;
????????[MessageHeader(MustUnderstand?=?true)]
????????public?string?FileName;
????????[MessageBodyMember(Order?=?1)]
????????public?Stream?FileData;
????}
定義FileUploadMessage類的目的是因為第三個限制,要不然文件名和存放路徑就沒辦法傳遞給WCF了,根據(jù)第二個限制,文件數(shù)據(jù)是用System.IO.Stream來傳遞的
接口方法只有一個,就是上傳文件,注意方法參數(shù)是FileUploadMessage
接口實現(xiàn)類文件的代碼如下:
?public?class?UpLoadService?:?IUpLoadService
????{
????????public?void?UploadFile(FileUploadMessage?request)
????????{
????????????string?uploadFolder?=?@"C:\kkk\";
????????????string?savaPath?=?request.SavePath;
????????????string?dateString?=?DateTime.Now.ToShortDateString()?+?@"\";
????????????string?fileName?=?request.FileName;
????????????Stream?sourceStream?=?request.FileData;
????????????FileStream?targetStream?=?null;
???????????
????????????if?(!sourceStream.CanRead)
????????????{
????????????????throw?new?Exception("數(shù)據(jù)流不可讀!");
????????????}
????????????if?(savaPath?==?null)?savaPath?=?@"Photo\";
????????????if?(!savaPath.EndsWith("\\"))?savaPath?+=?"\\";
????????????uploadFolder?=?uploadFolder?+?savaPath?+?dateString;
????????????if?(!Directory.Exists(uploadFolder))
????????????{
????????????????Directory.CreateDirectory(uploadFolder);
????????????}
????????????string?filePath?=?Path.Combine(uploadFolder,?fileName);
????????????using?(targetStream?=?new?FileStream(filePath,?FileMode.Create,?FileAccess.Write,?FileShare.None))
????????????{
????????????????//read?from?the?input?stream?in?4K?chunks
????????????????//and?save?to?output?stream
????????????????const?int?bufferLen?=?4096;
????????????????byte[]?buffer?=?new?byte[bufferLen];
????????????????int?count?=?0;
????????????????while?((count?=?sourceStream.Read(buffer,?0,?bufferLen))?>?0)
????????????????{
????????????????????targetStream.Write(buffer,?0,?count);
????????????????}
????????????????targetStream.Close();
????????????????sourceStream.Close();
????????????}
????????}
????}
實現(xiàn)的功能是到指定目錄下按照日期進行目錄劃分,然后以傳過來的文件名保存文件。
這篇文章最主要的地方就是下面的Web.Config配置:
????<bindings>
??????<basicHttpBinding>
????????<binding?name="FileTransferServicesBinding"?maxReceivedMessageSize="9223372036854775807"
??????????messageEncoding="Mtom"?transferMode="Streamed"?sendTimeout="00:10:00"?/>
??????????</basicHttpBinding>
????</bindings>
????<services>
??????<service?behaviorConfiguration="UploadWcfService.UpLoadServiceBehavior"
????????name="UploadWcfService.UpLoadService">
????????<endpoint?address=""?binding="basicHttpBinding"?bindingConfiguration="FileTransferServicesBinding"?contract="UploadWcfService.IUpLoadService">
????????</endpoint>
????????<endpoint?address="mex"?binding="mexHttpBinding"?contract="IMetadataExchange"?/>
??????</service>
????</services>
????<behaviors>
??????<serviceBehaviors>
????????<behavior?name="UploadWcfService.UpLoadServiceBehavior">
??????????<serviceMetadata?httpGetEnabled="true"?/>
??????????<serviceDebug?includeExceptionDetailInFaults="false"?/>
????????</behavior>
??????</serviceBehaviors>
????</behaviors>
??</system.serviceModel>
配置要遵循上面的第一條和第四條限制,因為默認.net只能傳4M的文件,所以要在
<System.Web>配置節(jié)下面加上<httpRuntimemaxRequestLength="2097151" />
這樣WCFService就完成了,新建一個Console項目或者Web項目測試一下。要注意的
是Client端的配置必須要和服務端一樣,實例程序在這里下載。
總結
- 上一篇: redhat下使用mrtg监控主机流量
- 下一篇: 使shell用结构化命令