1
+ <% @ WebHandler Language= " C#" Class = " Handler" %>
2
+
3
+ using System;
4
+ using System.Web;
5
+ using System.Collections.Generic;
6
+ using System.IO;
7
+ using System.Runtime.Serialization;
8
+
9
+ // app.js
10
+ /*
11
+ var isOnGitHub = window.location.hostname === 'blueimp.github.io',
12
+ url = 'server/asp_net/Handler.ashx';
13
+ */
14
+
15
+ //main.js
16
+ /*
17
+ // Initialize the jQuery File Upload widget:
18
+ $('#fileupload').fileupload({
19
+ // Uncomment the following to send cross-domain cookies:
20
+ //xhrFields: {withCredentials: true},
21
+ url: 'server/asp_net/Handler.ashx'
22
+ });
23
+ */
24
+
25
+ public class Handler : IHttpAsyncHandler
26
+ {
27
+ private static readonly FilesDisposition FILES_DISPOSITION = FilesDisposition.Absolute;
28
+ private static readonly string FILES_PATH = @"c:\temp\uploader";
29
+
30
+ private static readonly string FILE_QUERY_VAR = "file";
31
+ private static readonly string FILE_GET_CONTENT_TYPE = "application/octet-stream";
32
+
33
+ private static readonly int ATTEMPTS_TO_WRITE = 3;
34
+ private static readonly int ATTEMPT_WAIT = 100; //msec
35
+
36
+ private static readonly int BUFFER_SIZE = 4 * 1024 * 1024;
37
+
38
+ private enum FilesDisposition
39
+ {
40
+ ServerRoot,
41
+ HandlerRoot,
42
+ Absolute
43
+ }
44
+
45
+ private static class HttpMethods
46
+ {
47
+ public static readonly string GET = "GET";
48
+ public static readonly string POST = "POST";
49
+ public static readonly string DELETE = "DELETE";
50
+ }
51
+
52
+ [DataContract]
53
+ private class FileResponse
54
+ {
55
+ [DataMember]
56
+ public string name;
57
+ [DataMember]
58
+ public long size;
59
+ [DataMember]
60
+ public string type;
61
+ [DataMember]
62
+ public string url;
63
+ [DataMember]
64
+ public string error;
65
+ [DataMember]
66
+ public string deleteUrl;
67
+ [DataMember]
68
+ public string deleteType;
69
+ }
70
+
71
+ [DataContract]
72
+ private class UploaderResponse
73
+ {
74
+ [DataMember]
75
+ public FileResponse[] files;
76
+
77
+ public UploaderResponse(FileResponse[] fileResponses)
78
+ {
79
+ files = fileResponses;
80
+ }
81
+ }
82
+
83
+ private static string CreateFileUrl(HttpRequest request, string fileName, FilesDisposition filesDisposition)
84
+ {
85
+ switch (filesDisposition)
86
+ {
87
+ case FilesDisposition.ServerRoot:
88
+ // 1. files directory lies in root directory catalog WRONG
89
+ return String.Format("{0}{1}/{2}", request.Url.GetLeftPart(UriPartial.Authority),
90
+ FILES_PATH, Path.GetFileName(fileName));
91
+
92
+ case FilesDisposition.HandlerRoot:
93
+ // 2. files directory lays in current page catalog WRONG
94
+ return String.Format("{0}{1}{2}/{3}", request.Url.GetLeftPart(UriPartial.Authority),
95
+ Path.GetDirectoryName(request.CurrentExecutionFilePath).Replace(@"\", @"/"), FILES_PATH, Path.GetFileName(fileName));
96
+
97
+ case FilesDisposition.Absolute:
98
+ // 3. files directory lays anywhere YEAH
99
+ return String.Format("{0}?{1}={2}", request.Url.AbsoluteUri, FILE_QUERY_VAR, HttpUtility.UrlEncode(Path.GetFileName(fileName)));
100
+ default:
101
+ return String.Empty;
102
+ }
103
+ }
104
+
105
+ private static FileResponse CreateFileResponse(HttpRequest request, string fileName, long size, string error)
106
+ {
107
+ return new FileResponse()
108
+ {
109
+ name = Path.GetFileName(fileName),
110
+ size = size,
111
+ type = String.Empty,
112
+ url = CreateFileUrl(request, fileName, FILES_DISPOSITION),
113
+ error = error,
114
+ deleteUrl = CreateFileUrl(request, fileName, FilesDisposition.Absolute),
115
+ deleteType = HttpMethods.DELETE
116
+ };
117
+ }
118
+
119
+ private static void SerializeUploaderResponse(HttpResponse response, List<FileResponse > fileResponses)
120
+ {
121
+
122
+ var Serializer = new global::System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(UploaderResponse));
123
+
124
+ Serializer.WriteObject(response.OutputStream, new UploaderResponse(fileResponses.ToArray()));
125
+ }
126
+
127
+ private static void FromStreamToStream(Stream source, Stream destination)
128
+ {
129
+ int BufferSize = source.Length >= BUFFER_SIZE ? BUFFER_SIZE : (int)source.Length;
130
+ long BytesLeft = source.Length;
131
+
132
+ byte[] Buffer = new byte[BufferSize];
133
+
134
+ int BytesRead = 0;
135
+
136
+ while (BytesLeft > 0)
137
+ {
138
+ BytesRead = source.Read(Buffer, 0, BytesLeft > BufferSize ? BufferSize : (int)BytesLeft);
139
+
140
+ destination.Write(Buffer, 0, BytesRead);
141
+
142
+ BytesLeft -= BytesRead;
143
+ }
144
+ }
145
+
146
+ #region IHttpAsyncHandler
147
+
148
+ private ProcessRequestDelegate RequestDelegate;
149
+ private delegate void ProcessRequestDelegate(HttpContext context);
150
+
151
+ public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
152
+ {
153
+ RequestDelegate = new ProcessRequestDelegate(ProcessRequest);
154
+
155
+ return RequestDelegate.BeginInvoke(context, cb, extraData);
156
+ }
157
+
158
+ public void EndProcessRequest(IAsyncResult result)
159
+ {
160
+ RequestDelegate.EndInvoke(result);
161
+ }
162
+
163
+ public bool IsReusable
164
+ {
165
+ get { return false; }
166
+ }
167
+
168
+ public void ProcessRequest(HttpContext context)
169
+ {
170
+ string FilesPath;
171
+
172
+ switch (FILES_DISPOSITION)
173
+ {
174
+ case FilesDisposition.ServerRoot:
175
+ FilesPath = context.Server.MapPath(FILES_PATH);
176
+ break;
177
+ case FilesDisposition.HandlerRoot:
178
+ FilesPath = context.Server.MapPath(Path.GetDirectoryName(context.Request.CurrentExecutionFilePath) + FILES_PATH);
179
+ break;
180
+ case FilesDisposition.Absolute:
181
+ FilesPath = FILES_PATH;
182
+ break;
183
+ default:
184
+ context.Response.StatusCode = 500;
185
+ context.Response.StatusDescription = "Configuration error (FILES_DISPOSITION)";
186
+ return;
187
+ }
188
+
189
+ // prepare directory
190
+ if (!Directory.Exists(FilesPath))
191
+ {
192
+ Directory.CreateDirectory(FilesPath);
193
+ }
194
+
195
+
196
+ string QueryFileName = context.Request[FILE_QUERY_VAR];
197
+ string FullFileName = null;
198
+ string ShortFileName = null;
199
+
200
+ //if (!String.IsNullOrEmpty(QueryFileName))
201
+ if (QueryFileName != null) // param specified, but maybe in wrong format (empty). else user will download json with listed files
202
+ {
203
+ ShortFileName = HttpUtility.UrlDecode(QueryFileName);
204
+ FullFileName = String.Format(@"{0}\{1}", FilesPath, ShortFileName);
205
+
206
+ if (QueryFileName.Trim().Length == 0 || !File.Exists(FullFileName))
207
+ {
208
+ context.Response.StatusCode = 404;
209
+ context.Response.StatusDescription = "File not found";
210
+
211
+ context.Response.End();
212
+ return;
213
+ }
214
+ }
215
+
216
+ if (context.Request.HttpMethod.ToUpper() == HttpMethods.GET)
217
+ {
218
+ if (FullFileName != null)
219
+ {
220
+ context.Response.ContentType = FILE_GET_CONTENT_TYPE; // http://www.digiblog.de/2011/04/android-and-the-download-file-headers/ :)
221
+ context.Response.AddHeader("Content-Disposition", String.Format("attachment; filename={0}{1}", Path.GetFileNameWithoutExtension(ShortFileName), Path.GetExtension(ShortFileName).ToUpper()));
222
+
223
+ using (FileStream FileReader = new FileStream(FullFileName, FileMode.Open, FileAccess.Read))
224
+ {
225
+ FromStreamToStream(FileReader, context.Response.OutputStream);
226
+
227
+ context.Response.OutputStream.Close();
228
+ }
229
+
230
+ context.Response.End();
231
+ return;
232
+ }
233
+ else
234
+ {
235
+ List<FileResponse > FileResponseList = new List<FileResponse >();
236
+
237
+ string[] FileNames = Directory.GetFiles(FilesPath);
238
+
239
+ foreach (string FileName in FileNames)
240
+ {
241
+ FileResponseList.Add(CreateFileResponse(context.Request, FileName, new FileInfo(FileName).Length, String.Empty));
242
+ }
243
+
244
+ SerializeUploaderResponse(context.Response, FileResponseList);
245
+ }
246
+ }
247
+ else if (context.Request.HttpMethod.ToUpper() == HttpMethods.POST)
248
+ {
249
+ List<FileResponse > FileResponseList = new List<FileResponse >();
250
+
251
+ for (int FileIndex = 0; FileIndex < context.Request.Files.Count; FileIndex++)
252
+ {
253
+ HttpPostedFile File = context.Request.Files[FileIndex];
254
+
255
+ string FileName = String.Format(@"{0}\{1}", FilesPath, Path.GetFileName(File.FileName));
256
+ string ErrorMessage = String.Empty;
257
+
258
+ for (int Attempts = 0; Attempts < ATTEMPTS_TO_WRITE; Attempts++)
259
+ {
260
+ ErrorMessage = String.Empty;
261
+
262
+ if (System.IO.File.Exists(FileName))
263
+ {
264
+ FileName = String.Format(@"{0}\{1}_{2:yyyyMMddHHmmss.fff}{3}", FilesPath, Path.GetFileNameWithoutExtension(FileName), DateTime.Now, Path.GetExtension(FileName));
265
+ }
266
+
267
+ try
268
+ {
269
+ using (Stream FileStreamWriter = new FileStream(FileName, FileMode.CreateNew, FileAccess.Write))
270
+ {
271
+ FromStreamToStream(context.Request.InputStream, FileStreamWriter);
272
+ }
273
+ }
274
+ catch (Exception exception)
275
+ {
276
+ ErrorMessage = exception.Message;
277
+ System.Threading.Thread.Sleep(ATTEMPT_WAIT);
278
+ continue;
279
+ }
280
+
281
+ break;
282
+ }
283
+
284
+ FileResponseList.Add(CreateFileResponse(context.Request, File.FileName, File.ContentLength, ErrorMessage));
285
+ }
286
+
287
+ SerializeUploaderResponse(context.Response, FileResponseList);
288
+ }
289
+ else if (context.Request.HttpMethod.ToUpper() == HttpMethods.DELETE)
290
+ {
291
+ bool SuccessfullyDeleted = true;
292
+
293
+ try
294
+ {
295
+ File.Delete(FullFileName);
296
+ }
297
+ catch
298
+ {
299
+ SuccessfullyDeleted = false;
300
+ }
301
+
302
+ context.Response.Write(String.Format("{{\"{0}\":{1}}}", ShortFileName, SuccessfullyDeleted.ToString().ToLower()));
303
+ }
304
+ else
305
+ {
306
+ context.Response.StatusCode = 405;
307
+ context.Response.StatusDescription = "Method not allowed";
308
+ context.Response.End();
309
+
310
+ return;
311
+ }
312
+
313
+
314
+ context.Response.End();
315
+ }
316
+
317
+ #endregion
318
+
319
+ }
0 commit comments