Invoke 方法:
public Task Invoke(HttpContext context)
{
// Check if there is a SendFile feature already present
if (context.GetFeature<IHttpSendFileFeature>() == null)
{
context.SetFeature<IHttpSendFileFeature>(new SendFileWrapper(context.Response.Body, _logger));
}
return _next(context);
}
这里是对 IHttpSendFileFeature 赋值 接口只有一个方法:
public interface IHttpSendFileFeature
{
Task SendFileAsync(string path, long offset, long? length, CancellationToken cancellation);
}
具体的实现代码:
public async Task SendFileAsync(string fileName, long offset, long? length, CancellationToken cancel)
{
cancel.ThrowIfCancellationRequested();
//此处有一些判断 如 是否超过文件长度
#if ASPNET50
Stream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 1024 * 64,
FileOptions.Asynchronous | FileOptions.SequentialScan);
#else
// TODO: Bring back async when the contract gets it
Stream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 1024 * 64);
#endif
try
{
fileStream.Seek(offset, SeekOrigin.Begin);
if (_logger.IsEnabled(LogLevel.Verbose))
{
_logger.WriteVerbose(string.Format("Copying bytes {0}-{1} of file {2} to response body", offset, length != null ? (offset + length).ToString() : "*", fileName));
}
await StreamCopyOperation.CopyToAsync(fileStream, _output, length, cancel);
}
finally
{
fileStream.Dispose();
}
}
为什么有offset 和 length? 可以获取文件的一部分 如:特别大的一个文件 可以用多线程每个线程获取文件的一部分 最后合并成完整的文件。
断点续传如:迅雷等就是利用这个来实现的。
核心的代码就这两行
fileStream.Seek(offset, SeekOrigin.Begin);
await StreamCopyOperation.CopyToAsync(fileStream, _output, length, cancel);
其中 _output 是 context.Response.Body。
具体的使用例子:
await response.SendFileAsync("testFile.txt", 1, 3, CancellationToken.None);//3个字节
await response.SendFileAsync("testFile.txt");//整个文件
浙公网安备 33010602011771号