7
7
using System . Threading . Tasks ;
8
8
using Microsoft . AspNetCore . Http . Extensions ;
9
9
using Microsoft . AspNetCore . Http . Features ;
10
+ using Microsoft . Extensions . FileProviders ;
10
11
11
12
namespace Microsoft . AspNetCore . Http
12
13
{
@@ -15,13 +16,73 @@ namespace Microsoft.AspNetCore.Http
15
16
/// </summary>
16
17
public static class SendFileResponseExtensions
17
18
{
19
+ /// <summary>
20
+ /// Sends the given file using the SendFile extension.
21
+ /// </summary>
22
+ /// <param name="response"></param>
23
+ /// <param name="file">The file.</param>
24
+ public static Task SendFileAsync ( this HttpResponse response , IFileInfo file ,
25
+ CancellationToken cancellationToken = default ( CancellationToken ) )
26
+ {
27
+ if ( response == null )
28
+ {
29
+ throw new ArgumentNullException ( nameof ( response ) ) ;
30
+ }
31
+ if ( file == null )
32
+ {
33
+ throw new ArgumentNullException ( nameof ( file ) ) ;
34
+ }
35
+
36
+ return response . SendFileAsync ( file , 0 , null , cancellationToken ) ;
37
+ }
38
+
39
+ /// <summary>
40
+ /// Sends the given file using the SendFile extension.
41
+ /// </summary>
42
+ /// <param name="response"></param>
43
+ /// <param name="file">The file.</param>
44
+ /// <param name="offset">The offset in the file.</param>
45
+ /// <param name="count">The number of bytes to send, or null to send the remainder of the file.</param>
46
+ /// <param name="cancellationToken"></param>
47
+ /// <returns></returns>
48
+ public static async Task SendFileAsync ( this HttpResponse response , IFileInfo file , long offset , long ? count ,
49
+ CancellationToken cancellationToken = default ( CancellationToken ) )
50
+ {
51
+ if ( response == null )
52
+ {
53
+ throw new ArgumentNullException ( nameof ( response ) ) ;
54
+ }
55
+ if ( file == null )
56
+ {
57
+ throw new ArgumentNullException ( nameof ( file ) ) ;
58
+ }
59
+ CheckRange ( offset , count , file . Length ) ;
60
+
61
+ if ( string . IsNullOrEmpty ( file . PhysicalPath ) )
62
+ {
63
+ using ( var fileContent = file . CreateReadStream ( ) )
64
+ {
65
+ if ( offset > 0 )
66
+ {
67
+ fileContent . Seek ( offset , SeekOrigin . Begin ) ;
68
+ }
69
+ await StreamCopyOperation . CopyToAsync ( fileContent , response . Body , count , cancellationToken ) ;
70
+ }
71
+ }
72
+ else
73
+ {
74
+ await response . SendFileAsync ( file . PhysicalPath , offset , count , cancellationToken ) ;
75
+ }
76
+ }
77
+
18
78
/// <summary>
19
79
/// Sends the given file using the SendFile extension.
20
80
/// </summary>
21
81
/// <param name="response"></param>
22
82
/// <param name="fileName">The full path to the file.</param>
23
83
/// <returns></returns>
24
- public static Task SendFileAsync ( this HttpResponse response , string fileName )
84
+ public static Task SendFileAsync ( this HttpResponse response , string fileName ,
85
+ CancellationToken cancellationToken = default ( CancellationToken ) )
25
86
{
26
87
if ( response == null )
27
88
{
@@ -33,7 +94,7 @@ public static Task SendFileAsync(this HttpResponse response, string fileName)
33
94
throw new ArgumentNullException ( nameof ( fileName ) ) ;
34
95
}
35
96
36
- return response . SendFileAsync ( fileName , 0 , null , CancellationToken . None ) ;
97
+ return response . SendFileAsync ( fileName , 0 , null , cancellationToken ) ;
37
98
}
38
99
39
100
/// <summary>
@@ -42,10 +103,11 @@ public static Task SendFileAsync(this HttpResponse response, string fileName)
42
103
/// <param name="response"></param>
43
104
/// <param name="fileName">The full path to the file.</param>
44
105
/// <param name="offset">The offset in the file.</param>
45
- /// <param name="count">The number of types to send, or null to send the remainder of the file.</param>
106
+ /// <param name="count">The number of bytes to send, or null to send the remainder of the file.</param>
46
107
/// <param name="cancellationToken"></param>
47
108
/// <returns></returns>
48
- public static Task SendFileAsync ( this HttpResponse response , string fileName , long offset , long ? count , CancellationToken cancellationToken )
109
+ public static Task SendFileAsync ( this HttpResponse response , string fileName , long offset , long ? count ,
110
+ CancellationToken cancellationToken = default ( CancellationToken ) )
49
111
{
50
112
if ( response == null )
51
113
{
@@ -67,21 +129,13 @@ public static Task SendFileAsync(this HttpResponse response, string fileName, lo
67
129
}
68
130
69
131
// Not safe for overlapped writes.
70
- private static async Task SendFileAsync ( Stream outputStream , string fileName , long offset , long ? length , CancellationToken cancel )
132
+ private static async Task SendFileAsync ( Stream outputStream , string fileName , long offset , long ? count ,
133
+ CancellationToken cancel = default ( CancellationToken ) )
71
134
{
72
135
cancel . ThrowIfCancellationRequested ( ) ;
73
136
74
137
var fileInfo = new FileInfo ( fileName ) ;
75
- if ( offset < 0 || offset > fileInfo . Length )
76
- {
77
- throw new ArgumentOutOfRangeException ( nameof ( offset ) , offset , string . Empty ) ;
78
- }
79
-
80
- if ( length . HasValue &&
81
- ( length . Value < 0 || length . Value > fileInfo . Length - offset ) )
82
- {
83
- throw new ArgumentOutOfRangeException ( nameof ( length ) , length , string . Empty ) ;
84
- }
138
+ CheckRange ( offset , count , fileInfo . Length ) ;
85
139
86
140
int bufferSize = 1024 * 16 ;
87
141
@@ -96,8 +150,20 @@ private static async Task SendFileAsync(Stream outputStream, string fileName, lo
96
150
using ( fileStream )
97
151
{
98
152
fileStream . Seek ( offset , SeekOrigin . Begin ) ;
153
+ await StreamCopyOperation . CopyToAsync ( fileStream , outputStream , count , cancel ) ;
154
+ }
155
+ }
99
156
100
- await StreamCopyOperation . CopyToAsync ( fileStream , outputStream , length , cancel ) ;
157
+ private static void CheckRange ( long offset , long ? count , long fileLength )
158
+ {
159
+ if ( offset < 0 || offset > fileLength )
160
+ {
161
+ throw new ArgumentOutOfRangeException ( nameof ( offset ) , offset , string . Empty ) ;
162
+ }
163
+ if ( count . HasValue &&
164
+ ( count . Value < 0 || count . Value > fileLength - offset ) )
165
+ {
166
+ throw new ArgumentOutOfRangeException ( nameof ( count ) , count , string . Empty ) ;
101
167
}
102
168
}
103
169
}
0 commit comments