ماژول دانلودر برای ASP.NET
۱۳۹۰/۱۲/۰۶ ۱۳:۰۴ منتشر شده در تاریخ : ۱۳۹۰/۱۲/۰۶ دسته بندی : معرفی ، ASP.NET ، Download ، OpenSource 3
- مقدمه
همچنین یک نیاز دیگر هم پیش می آید و آن محدود کردن پهنای باند مصرفی برای دانلود است. که در حالت عادی و ارسال فایل از طریق دستورات asp.net این کار امکان پذیر نیست.
- معرفی
مجموعه کلاسهای ResumableDownload چندین کار مخلتف را انجام می دهد که با کنار هم قرار دادن آنها به مقصودمان می رسیم.
- طریقه استفاده
اولین قدیم شناسایی درخواست کاربر است. این درخواست معمولا توسط یک نرم افزار دانلودر مانند IDM انجام شده است. هدف در اینجا شناسایی هدر های ارسالی است که توسط یکی از متدهای کلاس HeadersParser انجام می شود.
قدم دوم باید اطلاعات فایلی که قرار است دانلود بشود توسط کلاس DownloadDataInfo جمع آوری شود. یکی از سازنده های کلاس اطلاعات فایل را دریافت می کند باید مورد استفاده قرار گیرد. سپس خروجی متد مورد استفاده از HeadersParser باید به کلاس DownloadDataInfo اطلاع داده شود و این کار با استفاده از متد InitializeRanges آن انجام می شود.
قدم سوم بررسی صحت درخواست دانلود است. این کار توسط متد های Validate کلاس HeadersParser انجام می شود. این کار از این جهت مهم است که ممکن است فایل در سرور تغییر داده شده باشد ولی کاربر سعی دارد تا همچنان به دانلود نسخه قدیمی که ناقص انجام شده بود ادامه دهد.
قدم اختیاری در این بین اعمال محدودیت در پهنای باند دانلود فایل برای کاربر است. این محدودیت توسط کلاس UserSpeedLimitManager قابل اعمال است. در آزمایشاتی که من انجام دادم مشخص شد که در هر صورت استفاده از این کلاس بار زیادی را از دوش سرور بر می دارد. این بدان علت است که در حالت بدون محدودیت سرور تمام فایل را از دیسک خوانده و به یکباره به بافر انتظار می فرستد, این عملیات یکباره بار زیادی بر سرور وارد می کند. همچنین مشخص شد که گذاشتن محدودیت حتی در حد 2MB/s می تواند تاثیر زیادی در افزایش بازدهی سرور داشته باشد.
قدم نهایی ارسال فایل به کاربر طبق درخواست وی که از طرق متد ProcessDownload کلاس DownloadProcess انجام می شود.
در ادامه یک مثال کامل را مشاهده می کنید. در این مثال نام فایل به عنوان ورودی ارسال می شود, سیستم این فایل را از مسیر برنامه یافته و برای کاربر ارسال می کند.
برای مثال آدرس به این صورت خواهد بود: http://localhost:5200/ResumableDownload.ashx?file=sample.zip
// 50 KB limit const int DownloadLimit = 50 * 1024; public void ProcessRequest(HttpContext context) { // Accepting user request // reading the query var fileNameQuery = context.Request.QueryString["file"]; // validating the request if (string.IsNullOrEmpty(fileNameQuery)) { InvalidRequest(context, "Invalid request! Specify file name in url e.g.: ResumableDownload.ashx?file=sample.zip"); return; } // the physical file address path var fileName = context.Server.MapPath(fileNameQuery); if (!File.Exists(fileName)) { InvalidRequest(context, "File does not exists!"); return; } // reading file info var fileInfo = new FileInfo(fileName); var fileLength = fileInfo.Length; // Download information class var downloadInfo = new DownloadDataInfo(fileName); // Reading request download range var requestedRanges = HeadersParser.ParseHttpRequestHeaderMultipleRange(context.Request, fileLength); // apply the ranges to the download info downloadInfo.InitializeRanges(requestedRanges); string etagMatched; int outcomeStausCode = 200; // validating the ranges specified if (!HeadersParser.ValidatePartialRequest(context.Request, downloadInfo, out etagMatched, ref outcomeStausCode)) { // the request is invalid, this is the invalid code context.Response.StatusCode = outcomeStausCode; // show to the client what is the real ETag if (!string.IsNullOrEmpty(etagMatched)) context.Response.AppendHeader("ETag", etagMatched); // stop the preoccess // but don't hassle with error messages return; } // user ID, or IP or anything you use to identify the user var userIP = context.Request.UserHostAddress; // limiting the download speed manager and the speed limit UserSpeedLimitManager.StartNewDownload(downloadInfo, userIP, DownloadLimit); // It is very important to destory the DownloadProcess object // Here the using block does it for us. using (var process = new DownloadProcess(downloadInfo)) { // start the download var state = process.ProcessDownload(context.Response); // checking the state of the download if (state == DownloadProcess.DownloadProcessState.PartFinished) { // all parts of download are finish, do something here! } } }
- دانلود
کدهای این پروژه به صورت آنلاین در این آدرس در دسترس هستند.
چندین کانکشن همزمان برای دانلود در حالی که کاربر به 50KB/s محدود شده است |
- مشکلات احتمالی
- کدهای استفاده شده از سایر نویسندگان
نسخه ابتدایی و قدیمی ZipHandler در زبان vb.net که چند سال پیش این ماژول ها بر اساس آن تبدیل و تهیه شد. اینجا.
بسیار عالی و کاربردی.ممنون/
پاسخحذفسلام استاد عزیز و محترم
پاسخحذفمن مدتهاست که دنبال این کلاس بودم و از آنجا که در مورد استفاده از کلاس های مشابه به مشکلات زیادی برخوردم اگر اجازه بفرمایید در مورد این Handler به بحث و گفتگو بنشینیم تا تمامی مشکلات احتمالی در مورد آن را مرتفع کنیم.
سوال 1: چرا Handler؟
آیا برای استفاده از Handler دلیل خاصی وجود دارد؟
میشه به صورت تخصصی در این زمینه توضیح بدید؟
آیا نمیشد همچون گذشته از یک کلاس برای دانلود استفاده کرد؟
آیا استفاده از Handler در مورد دانلود دارای مزیت خاصی است؟
سوال 2 : آیا این کلاس فایل های بزرگ به طور مثال 5 گیگ را ساپورت می کند؟
سوال 3:آیا بخش بخش دانلود کردن قسمت های مختلف فایل توسط IDM توسط ما باید مدیریت شود یا توسط خود IDM این قضیه Handle می گردد؟
اگر توسط ماست کدام قسمت کد این کار را انجام می دهد و چگونه ؟
سوال 4:در گذشته از Handler ی دیگر با کدی متفاوت برای دانلود فایل استفاده می کردم که در ابتدا به ظاهر همه چیش ok بود.
اما پس از اینکه یک شرط کوچک رو در اول Handler اضافه می کردم (مثلا ولید بودن کاربر) قابلیت MultiThreading در IDM ازبین می رفت و واقعاً این موضوع برایم کلافه کننده شده بود؟
آیا چنین شرطی رو میشه به این Handler اضافه نمود؟
سوال 5:در کلاس های گذشته مشکلی که وجود داشت این بود که گاهی کاربران تماس می گرفتند و می گفتند فایل ناقص دانلود می شود و Error crc می دهد.
آیا چنین مشکلی در مورد این Handler وجود ندارد؟
دلیل بوجود آمدن این ارور چه بود؟
با تشکر از حسن توجه و رسیدگی شما
همچنین تشکر مجدد برای به روز رسانی این کلاس توسط شما که به جرات می توان گفت نمونه به روز آن وجود ندارد
سلام, شما لطف دارید.
پاسخحذف1- Handler دسترسی سطح پایینی را بدون سربار اضافه در اختیار قرار می ده. و چون دانلود هم نیاز به کار اضافی ندارد بهترین جا برای انجام عملیات دانلود همین جاست.
در ضمن این ماژول به Handler محدود نیستید, شعی مورد نیاز HttpContext است که در همه درخواستهای وب در دسترسی است.
2- اساسا این کلاس برای کار با فایلهای بزرگ طراحی شده چون در فایلهای کوچک این قابلیت ها کاربرد چندانی ندارد.
نکته مهم در اینجا مربوط تنظیم صحیح مدت زمان مجاز برای اجرای درخواستهای کاربر هست که توسط asp.net کنترل می شه. مقدار آن به طور پیش فرض 110 ثانیه است. مقدارش رو افزایش بدین تا مشکلی پیش نیاد. مقدار executionTimeout اینجا:
http://msdn.microsoft.com/en-us/library/e1f13641.aspx
همچنین جهت جلوگیری از سرباز اضافه حتما محدودیت پهنای باند رو اعمال کنید
3- توسط نرم افزار دانلودر کنترل می شود.
4- کد خودتون رو قبل از استفاده از این کلاسهای بنویسید. تنها کاری که نباید انجام دهید این است که اگر کاربر رو برای دانلود هدایت می کنید نباید چیزی در خروجی بنویسید و یا تغییری اعمال کنید. دانلودر کار خودش رو درست انجام می ده.
5- این همان چیزی است که در مورد 2 اشاره شد, با تنظیم زیاد مقدار executionTimeout موردی نباید پیش بیاد.
همچنین بهتره که executionTimeout رو فقط برای صفحه handler زیاد کنید (با استفاده از کانفیگ location).