WCF Streaming: Upload/Download Files Over HTTP
来源:互联网 发布:同方云计算战略发布会 编辑:程序博客网 时间:2024/06/06 18:03
http://www.codeproject.com/Articles/166763/WCF-Streaming-Upload-Download-Files-Over-HTTP
- Download source code - 17.6 KB
Purpose of this article
I have tried to transfer large files over HTTP to/from WCF, but I have faced problems in that I was not able to upload files more than 45 KB in size. I have Googled over www, but I did not find any ready-to-use sample code/solution. Using the explanations over the www and MSDN, I have tried many configuration setting combinations and finally succeeded in transferring large files (I have tested up to 1GB on IE6).
I would like to share my experience so as to support efforts of others in this direction and to invite review comments from the developer community.
Explanation
To transfer large files using “WCF service + HTTP”, we can use the following types of bindings:
- wsHttpBinding
- basicHttpBinding
In wsHttpBinding, we can set the transfermode
attribute as Buffered
, but there is a disadvantage in using this approach for large files, because it needs to put the entire file in memory before uploading/downloading, A large buffer is required on both the web client and the WCF service host. However, this approach is very useful for transferring small files, securely.
In basicHTTPBinding we can use the transfermode
as Streamed
so that the file can be transferred in the form of chunks. We have to ensure additional security mechanisms for transferring chunks. The security mechanisms are not explained in this posting.
Implementation: WCF Service
Create a new “WCF Service” project. Create a new service with the name TransferService. Now we will see an interface file “ITransferService” and a class file TransferService.cs. ITransferService
should have two methods, one for upload and one for download.
[ServiceContract]public interface ITransferService{ [OperationContract] RemoteFileInfo DownloadFile(DownloadRequest request); [OperationContract] void UploadFile(RemoteFileInfo request); }[MessageContract]public class DownloadRequest{ [MessageBodyMember] public string FileName;}[MessageContract]public class RemoteFileInfo : IDisposable{ [MessageHeader(MustUnderstand = true)] public string FileName; [MessageHeader(MustUnderstand = true)] public long Length; [MessageBodyMember(Order = 1)] public System.IO.Stream FileByteStream; public void Dispose() { if (FileByteStream != null) { FileByteStream.Close(); FileByteStream = null; } } }
public RemoteFileInfo DownloadFile(DownloadRequest request){ RemoteFileInfo result = new RemoteFileInfo(); try { string filePath = System.IO.Path.Combine(@"c:\Uploadfiles", request.FileName); System.IO.FileInfo fileInfo = new System.IO.FileInfo(filePath); // check if exists if (!fileInfo.Exists) throw new System.IO.FileNotFoundException("File not found", request.FileName); // open stream System.IO.FileStream stream = new System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read); // return result result.FileName = request.FileName; result.Length = fileInfo.Length; result.FileByteStream = stream; } catch (Exception ex) { } return result; } public void UploadFile(RemoteFileInfo request) { FileStream targetStream = null; Stream sourceStream = request.FileByteStream; string uploadFolder = @"C:\upload\"; string filePath = Path.Combine(uploadFolder, request.FileName); using (targetStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None)) { //read from the input stream in 65000 byte chunks const int bufferLen = 65000; byte[] buffer = new byte[bufferLen]; int count = 0; while ((count = sourceStream.Read(buffer, 0, bufferLen)) > 0) { // save to output stream targetStream.Write(buffer, 0, count); } targetStream.Close(); sourceStream.Close(); } }
Settings of “Web.Config” in the WCF Service
The following settings are most important for transferring large data:
ReaderQuotas
: We have to set the maximum sizes (this depends on our specific requirement). Here I have set to the maximum values where we can transfer data up to 2GB, as per MSDN/www documentation.<binding name="TransferService" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" transferMode="Streamed" > <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
A word about my experiences here: I have used the above settings alone and received the error “400 bad request” from the WCF service on the browser.
This error may occur due to many reasons: the reasons might be configuration mismatch between the web server and the WCF service, or an exception raised in the WCF service etc.
BindingConfiguration
: This attribute is not available by default in the endpoint section. When I added this attribute, the “400 bad request” exception disappeared and the upload and download executed well.<endpoint address="" binding="basicHttpBinding" bindingConfiguration="TransferService" contract ="ITransferService"></endpoint>
Along with the above settings,
HttpRuntime
settings should also be placed in the web.config file as below:<httpRuntime maxRequestLength="2097151" //Maxvalue useFullyQualifiedRedirectUrl="true" executionTimeout="14400" /> //can be configured as per the requirement.
Implementation: Web Server
Create a new “web site” project. Place a link button and a file upload control on the web page. Create one more button to upload the file. Add the reference of the WCF service in “Service References” with a suitable name, currently FileTransferServiceReference
.
The following changes need to be done in web.config after adding the service reference:
<binding name="BasicHttpBinding_ITransferService" closeTimeout="04:01:00" openTimeout="04:01:00" receiveTimeout="04:10:00" sendTimeout="04:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text" textEncoding="utf-8" transferMode="Streamed" useDefaultWebProxy="true"> <readerQuotas maxDepth="128" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" /> <security mode="None"> <transport clientCredentialType="None" proxyCredentialType="None" realm="" /> <message clientCredentialType="UserName" algorithmSuite="Default" /> </security></binding>
Increase the values for the readerQuotas
attribute and also increase the timeout settings.
The code-behind of the page is the following:
protected void LinkButton1_Click(object sender, EventArgs e){ try { FileTransferServiceReference.ITransferService clientDownload = new TransferServiceClient(); FileTransferServiceReference.DownloadRequest requestData = new DownloadRequest(); FileTransferServiceReference.RemoteFileInfo fileInfo = new RemoteFileInfo(); requestData.FileName = "codebase.zip"; fileInfo = clientDownload.DownloadFile(requestData); Response.BufferOutput = false; // to prevent buffering byte[] buffer = new byte[6500]; int bytesRead = 0; HttpContext.Current.Response.Clear(); HttpContext.Current.Response.ClearHeaders(); HttpContext.Current.Response.ContentType = "application/octet-stream"; HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + requestData.FileName); bytesRead = fileInfo.FileByteStream.Read(buffer, 0, buffer.Length); while (bytesRead > 0) { // Verify that the client is connected. if (Response.IsClientConnected) { Response.OutputStream.Write(buffer, 0, bytesRead); // Flush the data to the HTML output. Response.Flush(); buffer = new byte[6500]; bytesRead = fileInfo.FileByteStream.Read(buffer, 0, buffer.Length); } else { bytesRead = -1; } } } catch (Exception ex) { // Trap the error, if any. System.Web.HttpContext.Current.Response.Write("Error : " + ex.Message); } finally { Response.Flush(); Response.Close(); Response.End(); System.Web.HttpContext.Current.Response.Close(); }}protected void Button1_Click(object sender, EventArgs e){ if (FileUpload1.HasFile) { System.IO.FileInfo fileInfo = new System.IO.FileInfo(FileUpload1.PostedFile.FileName); FileTransferServiceReference.ITransferService clientUpload = new FileTransferServiceReference.TransferServiceClient(); FileTransferServiceReference.RemoteFileInfo uploadRequestInfo = new RemoteFileInfo(); using (System.IO.FileStream stream = new System.IO.FileStream(FileUpload1.PostedFile.FileName, System.IO.FileMode.Open, System.IO.FileAccess.Read)) { uploadRequestInfo.FileName = FileUpload1.FileName; uploadRequestInfo.Length = fileInfo.Length; uploadRequestInfo.FileByteStream = stream; clientUpload.UploadFile(uploadRequestInfo); //clientUpload.UploadFile(stream); } }}
Now build both the IDE projects and execute the web server project. This still works only for less than 50KB! If you select a large file to be uploaded, you will see a blank webpage.
Now, you need to add one more attribute, MaxRequestLength
, in the httpRuntime
section in the system.web
configuration file section, as below:
<httpRuntime maxRequestLength="2097150"/>
That is it! Now one can download and upload large files (I have tested up to ~1GB) from an IE6 browser over HTTP to a WCF service.
- WCF Streaming: Upload/Download Files Over HTTP
- libcurl http download upload
- Dynamic Adaptive Streaming over HTTP
- HTTP download of files over 2GB will stop exactly at 2GB and report as Done
- Dynamic Adaptive Streaming over HTTP Dataset
- mpeg-DASH (Dynamic Adaptive Streaming over HTTP)
- Dynamic Adaptive Streaming over HTTP Dataset
- VLC RTP Video Streaming over HTTP
- Dynamic Adaptive Streaming over HTTP Dataset
- Video streaming vs Progressive download or HTTP streaming
- Android HTTP Client: GET, POST, Download, Upload, Multipart Request
- http://club.amteam.org/upload-files/essence/880244_28412.RAR
- The difference of HLS and http Progressive download streaming
- DASH(Dynamic Adaptive Streaming over HTTP)自适应流媒体
- use python to download files from http servers
- DownLoad & Upload ScriptForm Program
- abap upload and download
- .NET Upload & Download image
- Linux下添加哭文件路径
- 3、函数和数组
- 为黑客设计的概率规划与贝叶斯方法
- UIScrollView控件的一些简单介绍
- 端口镜像 相关注意事项备忘
- WCF Streaming: Upload/Download Files Over HTTP
- Java自学总结之七图形用户接口
- C++线程同步的一种简单方法
- 自定义带加载中与加载失败的EmptyView的ListView
- linux 下应用程序的默认安装目录
- HTML5 datalist与动态邮箱地址实例
- 关于指针初始化的一些思考
- A Plug for UNIX(网络流模板题)
- 良少:编程能力层次模型