手把手教你實現(xiàn)WCF上傳文件
在優(yōu)酷上我想上傳一段視頻,你有想過會臺是怎么實現(xiàn)的嗎?這里我就為大家分析一下關于利用WCF上傳文件,在WCF沒出現(xiàn)之前,我一直使用用WebService來上傳文件,我不知道別人為什么要這么做,因為我們的文件服務器和網(wǎng)站后臺和網(wǎng)站前臺都不在同一個機器,操作人員覺得用FTP傳文件太麻煩,我就做一個專門用來上傳文件的WebService,把這個WebService部署在文件服務器上,然后在網(wǎng)站后臺調用這個WebService,把網(wǎng)站后臺頁面上傳上來的文件轉化為字節(jié)流傳給WebService,然后WebService把這個字節(jié)流保存文件到一個只允許靜態(tài)頁面的網(wǎng)站(靜態(tài)網(wǎng)站可以防止一些腳本木馬)。
#T#WebService來上傳文件存在的問題是效率不高,而且不能傳輸大數(shù)據(jù)量的文件,當然你可以用Wse中的MTOM來傳輸大文件,有了WCF就好多了,通過使用WCF傳遞Stream對象來傳遞大數(shù)據(jù)文件,但有一些限制:只有BasicHttpBinding、NetTcpBinding和NetNamedPipeBinding支持傳送流數(shù)據(jù)。流數(shù)據(jù)類型必須是可序列化的Stream或MemoryStream。傳遞時消息體(MessageBody)中不能包含其他數(shù)據(jù)。TransferMode的限制和MaxReceivedMessageSize的限制等。
下面具體實現(xiàn):新建一個WCFService,接口文件的代碼如下:
- [ServiceContract]
- publicinterfaceIUpLoadService
- {
- [OperationContract(Action="UploadFile",IsOneWay=true)]
- voidUploadFile(FileUploadMessagerequest);
- }
- [MessageContract]
- publicclassFileUploadMessage
- {
- [MessageHeader(MustUnderstand=true)]
- publicstringSavePath;
- [MessageHeader(MustUnderstand=true)]
- publicstringFileName;
- [MessageBodyMember(Order=1)]
- publicStreamFileData;
- }
定義FileUploadMessage類的目的是因為第三個限制,要不然文件名和存放路徑就沒辦法傳遞給WCF了,根據(jù)第二個限制,文件數(shù)據(jù)是用System.IO.Stream來傳遞的接口方法只有一個,就是WCF上傳文件,注意方法參數(shù)是FileUploadMessage接口實現(xiàn)類文件的代碼如下:
- publicclassUpLoadService:IUpLoadService
- {
- publicvoidUploadFile(FileUploadMessagerequest)
- {
- stringuploadFolder=@"C:\kkk\";
- stringsavaPath=request.SavePath;
- stringdateString=DateTime.Now.ToShortDateString()+@"\";
- stringfileName=request.FileName;
- StreamsourceStream=request.FileData;
- FileStreamtargetStream=null;
- if(!sourceStream.CanRead)
- {
- thrownewException("數(shù)據(jù)流不可讀!");
- }
- if(savaPath==null)savaPath=@"Photo\";
- if(!savaPath.EndsWith("\\"))savaPath+="\\";
- uploadFolderuploadFolder=uploadFolder+savaPath+dateString;
- if(!Directory.Exists(uploadFolder))
- {
- Directory.CreateDirectory(uploadFolder);
- }
- stringfilePath=Path.Combine(uploadFolder,fileName);
- using(targetStream=newFileStream(filePath,FileMode.Create,FileAccess.Write,FileShare.None))
- {
- //readfromtheinputstreamin4Kchunks
- //andsavetooutputstream
- constintbufferLen=4096;
- byte[]buffer=newbyte[bufferLen];
- intcount=0;
- while((count=sourceStream.Read(buffer,0,bufferLen))>0)
- {
- targetStream.Write(buffer,0,count);
- }
- targetStream.Close();
- sourceStream.Close();
- }
- }
- }
實現(xiàn)的功能是到指定目錄下按照日期進行目錄劃分,然后以傳過來的文件名保存文件。這篇文章最主要的地方就是下面的Web.Config配置:
- <system.serviceModel>
- <bindings>
- <basicHttpBinding>
- <bindingnamebindingname="FileTransferServicesBinding"maxReceivedMessageSize="9223372036854775807"
- messageEncoding="Mtom"transferMode="Streamed"sendTimeout="00:10:00"/>
- </basicHttpBinding>
- </bindings>
- <services>
- <servicebehaviorConfigurationservicebehaviorConfiguration="UploadWcfService.UpLoadServiceBehavior"
- name="UploadWcfService.UpLoadService">
- <endpointaddressendpointaddress=""binding="basicHttpBinding"bindingConfiguration="FileTransferServicesBinding"contract="UploadWcfService.IUpLoadService">
- </endpoint>
- <endpointaddressendpointaddress="mex"binding="mexHttpBinding"contract="IMetadataExchange"/>
- </service>
- </services>
- <behaviors>
- <serviceBehaviors>
- <behaviornamebehaviorname="UploadWcfService.UpLoadServiceBehavior">
- <serviceMetadatahttpGetEnabledserviceMetadatahttpGetEnabled="true"/>
- <serviceDebugincludeExceptionDetailInFaultsserviceDebugincludeExceptionDetailInFaults="false"/>
- </behavior>
- </serviceBehaviors>
- </behaviors>
- </system.serviceModel>