接触WebAPI一年多了,感觉是个承上启下,开创未来的技术。老一辈程序员写接口就像写方法一样,不需要了解太多网页的知识,却可以在浏览器中访问这些接口;由于是基于HTTP协议,因此不管是PC、手机还是嵌入式均可顺利访问。对于当下软件多终端的设计结构来说,这就像是量身订做的一样。
在开发的过程中遇到了一些问题,大部分都可通过百度找到解决方案,但是有一个问题却一直没有很好地解决,那就是文件下载速度的问题。
网上找到的WebAPI下载文件的代码大都是以下方式:
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Runtime.Remoting.Contexts;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using System.Web.Http.Cors;
using System.Net.Http.Headers;
namespace Service.Controller
{
public partial class APIController : ApiController
{
public HttpResponseMessage GetFileResponse(string FilePath, string FileName = null, string ContentType = "application/octet-stream")
{
FileStream fs;
HttpResponseMessage result;
fs = new FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
result = new HttpResponseMessage(System.Net.HttpStatusCode.OK) { Content = new StreamContent(fs) };
result.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(ContentType);
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = (null != FileName ? FileName : Path.GetFileName(FilePath));
return result;
}
}
}
这种方式虽然可以实现文件下载,但是下载速度实在太慢(在局域网中下载速度只有50K),稍大一点的文件就有可能导致客户端请求超时。
改为以下方式可实现高速下载的目的。在百兆局域网内实际测试可满速下载。
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Runtime.Remoting.Contexts;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using System.Web.Http.Cors;
using System.Net.Http.Headers;
namespace Service.Controller
{
public partial class APIController : ApiController
{
#region 辅助函数
public interface IWriteStreamToResponse<T>
{
T Suorce { get; set; }
void WriteToStream(Stream outputStream, HttpContent content, TransportContext context);
}
public class StreamFromFileName : IWriteStreamToResponse<string>
{
private string _suorce;
public string Suorce
{
get
{
return _suorce;
}
set
{
_suorce = value;
}
}
public async void WriteToStream(Stream outputStream, HttpContent content, TransportContext context)
{
try
{
var buffer = new byte[1024 * 1024 * 2];
using (var video = File.Open(_suorce, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var length = (int)video.Length;
var bytesRead = 1;
while (length > 0 && bytesRead > 0)
{
bytesRead = video.Read(buffer, 0, Math.Min(length, buffer.Length));
await outputStream.WriteAsync(buffer, 0, bytesRead);
length -= bytesRead;
}
}
}
catch (Exception ex)
{
return;
}
finally
{
outputStream.Close();
}
}
}
public class StreamFromBytes : IWriteStreamToResponse<Stream>
{
private Stream _source;
public Stream Suorce
{
get
{
return _source;
}
set
{
_source = value;
}
}
public async void WriteToStream(Stream outputStream, HttpContent content, TransportContext context)
{
try
{
var buffer = new byte[1024 * 1024 * 2];
using (var video = _source)
{
var length = (int)video.Length;
var bytesRead = 1;
while (length > 0 && bytesRead > 0)
{
bytesRead = video.Read(buffer, 0, Math.Min(length, buffer.Length));
await outputStream.WriteAsync(buffer, 0, bytesRead);
length -= bytesRead;
}
}
}
catch (Exception ex)
{
return;
}
finally
{
_source.Close();
outputStream.Close();
}
}
}
#endregion
public HttpResponseMessage GetFileResponse(string FilePath, string FileName = null, string ContentType = "application/octet-stream")
{
HttpResponseMessage response;
IWriteStreamToResponse<string> ResponseStreamWriter;
Action<Stream, HttpContent, TransportContext> sendMethod;
ResponseStreamWriter = new StreamFromFileName() { Suorce = FilePath };
sendMethod = ResponseStreamWriter.WriteToStream;
response = Request.CreateResponse();
response.Content = new System.Net.Http.PushStreamContent(sendMethod);
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(ContentType);
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = (null != FileName ? FileName : Path.GetFileName(FilePath));
return response;
}
}
}