مطالب
آشنایی با CLR: قسمت هفتم
کدهای IL و تایید آن ها

ساختار استکی
IL از ساختار استک استفاده می‌کند. به این معنی که تمامی دستور العمل‌ها داخل آن push شده و نتیجه‌ی اجرای آن‌ها pop می‌شوند. از آنجا که IL به طور مستقیم ارتباطی با ثبات‌ها ندارد، ایجاد زبانهای برنامه نویسی جدید بر اساس CLR بسیار راحت‌تر هست و عمل کامپایل، تبدیل کردن به کدهای IL می‌باشد.

بدون نوع بودن(Typeless)
از دیگر مزیت‌های آن این است که کدهای IL بدون نوع هستند. به این معنی که موقع افزودن دستورالعملی به داخل استک، دو عملگر وارد می‌شوند و هیچ جداسازی در رابطه با سیستم‌های 32 یا 64 بیت صورت نمی‌گیرد و موقع اجرای برنامه است که تصمیم می‌گیرد از چه عملگرهایی باید استفاده شود.

Virtual Address Space
بزرگترین مزیت این سیستم‌ها امنیت و مقاومت آن هاست. موقعی که تبدیل کد IL به سمت کد بومی صورت می‌گیرد، CLR فرآیندی را با نام verification یا تاییدیه، اجرا می‌کند. این فرآیند تمامی کدهای IL را بررسی می‌کند تا از امنیت کدها اطمینان کسب کند. برای مثال بررسی می‌کند که هر متدی صدا زده می‌شود با تعدادی پارامترهای صحیح صدا زده شود و به هر پارامتر آن نوع صحیحش پاس شود و مقدار بازگشتی هر متد به درستی استفاده شود. متادیتا شامل اطلاعات تمامی پیاده سازی‌ها و متدها و نوع هاست که در انجام تاییدیه مورد استفاده قرار می‌گیرد.
در ویندوز هر پروسه، یک آدرس مجازی در حافظه دارد و این جدا سازی حافظه و ایجاد یک حافظه مجازی کاری لازم اجراست. شما نمی‌توانید به کد یک برنامه اعتماد داشته باشید که از حد خود تخطی نخواهد کرد و فرآیند برنامه‌ی دیگر را مختل نخواهد کرد. با خواندن و نوشتن در یک آدرس نامعتبر حافظه، ما این اطمینان را کسب می‌کنیم که هیچ گاه تخطی در حافظه صورت نمی‌گیرد.
قبلا به طور مفصل در این مورد ذخیره سازی در حافظه صحبت کرده ایم.

Hosting
از آنجا که پروسه‌های ویندوزی به مقدار زیادی از منابع سیستم عامل نیاز دارند که باعث کاهش منابع و محدودیت در آن می‌شوند و نهایت کارآیی سیستم را پایین می‌آورد، ولی با کاهش تعدادی برنامه‌های در حال اجرا به یک پروسه‌ی واحد می‌توان کارآیی سیستم را بهبود بخشید و منابع کمتری مورد استفاده قرار می‌گیرند که این یکی دیگر از مزایای کدهای managed نسبت به unmanaged است. CLR در حقیقت این قابلیت را به شما می‌دهد تا چند برنامه‌ی مدیریت شده را در قالب یک پروسه به اجرا درآورید. هر برنامه‌ی مدیریت شده به طور پیش فرض بر روی یک appDomain اجرا می‌گردد و هر فایل EXE روی حافظه‌ی مجازی مختص خودش اجرا می‌شود. هر چند پروسه‌هایی از قبیل IIS و SQL Server که پروسه‌های CLR را پشتیبانی یا هاست می‌کنند می‌توانند تصمیم بگیرند که آیا appDomain‌ها را در یک پروسه‌ی واحد اجرا کنند یا خیر که در مقاله‌های آتی آن را بررسی می‌کنیم.

کد ناامن یا غیر ایمن UnSafe Code
به طور پیش فرض سی شارپ کدهای ایمنی را تولید می‌کند، ولی این اجازه را می‌دهد که اگر برنامه نویس بخواهد  کدهای ناامن بزند، قادر به انجام آن باشد. این کدهای ناامن دسترسی مستقیم به خانه‌های حافظه و دستکاری بایت هاست. این مورد قابلیت قدرتمندی است که به توسعه دهنده اجازه می‌دهد که با کدهای مدیریت نشده ارتباط برقرار کند یا یک الگوریتم با اهمیت زمانی بالا را جهت بهبود کارآیی، اجرا کند.
 هر چند یک کد ناامن سبب ریسک بزرگی می‌شود و می‌تواند وضعیت بسیاری از ساختارهای ذخیره شده در حافظه را به هم بزند و امنیت برنامه را تا حد زیادی کاهش دهد.  به همین دلیل سی شارپ نیاز دارد تا تمامی متدهایی که شامل کد unsafe هستند را با کلمه کلیدی unsafe علامت گذاری کند. همچنین کمپایلر سی شارپ نیاز دارد تا شما این کدها را با سوئیچ unsafe/ کامپایل کنید.

موقعیکه جیت تلاش دارد تا یک کد ناامن را کامپایل کند، اسمبلی را بررسی می‌کند که آیا این متد اجازه و تاییدیه آن را دارد یا خیر. آیا  System.Security.Permissions.SecurityPermission با فلگ SkipVerification مقدار دهی شده است یا خیر. اگر پاسخ مثبت بود JIT آن‌ها را کامپایل کرده و اجازه‌ی اجرای آن‌ها را می‌دهد. CLR به این کد اعتماد می‌کند و امیدوار است که آدرس دهی مستقیم و دستکاری بایت‌های حافظه موجب آسیبی نگردد. ولی اگر پاسخ منفی بود، یک استثناء از نوع System.InvalidProgramException یا System.Security.VerificationException را ایجاد می‌کند تا از اجرای این متد جلوگیری به عمل آید. در واقع کل برنامه خاتمه میابد ولی آسیبی به حافظه نمی‌زند.

پی نوشت: سیستم به  اسمبلی هایی که از روی ماشین یا از طریق شبکه  به اشتراک گذاشته می‌شوند اعتماد کامل میکند که این اعتماد شامل کدهای ناامن هم می‌شود ولی به طور پیش فرض به اسمبلی هایی از طریق اینترنت اجرا می‌شوند اجازه اجرای کدهای ناامن را نمی‌دهد و اگر شامل کدهای ناامن شود یکی از خطاهایی که در بالا به آن اشاره کردیم را صادر می‌کنند. در صورتی که مدیر یا کاربر سیستم اجازه اجرای آن را بدهد تمامی مسئولیت‌های این اجرا بر گردن اوست.

در این زمینه مایکروسافت ابزار سودمندی را با نام PEVerify .exe را معرفی کرده است که به بررسی تمامی متدهای یک اسمبلی پرداخته و در صورت وجود کد ناامن به شما اطلاع میدهد. بهتر است از این موضوع اطلاع داشته باشید که این ابزار نیاز دارد تا به متادیتاهای یک اسمبلی نیاز داشته باشید. باید این ابزار بتواند به تمامی ارجاعات آن دسترسی داشته باشد که در مورد عملیات بایندینگ در آینده بیشتر صحبت می‌کنیم.

IL و حقوق حق تالیف آن
بسیاری از توسعه دهندگان از اینکه IL هیچ شرایطی برای حفظ حق تالیف آن‌ها ایجاد نکرده است، ناراحت هستند. چرا که ابزارهای زیادی هستند که با انجام عملیات مهندسی معکوس می‌توانند به الگوریتم آنان دست پیدا کنند و میدانید که IL خیلی سطح پایین نیست و برگرداندن آن به شکل یک کد، کار راحت‌تری هست و بعضی ابزارها کدهای خوبی هم ارائه می‌کنند. از دست این ابزارها می‌توان به ILDisassembler و  JustDecompile اشاره کرد.
اگر علاقمند هستید این عیب را برطرف کنید، می‌توانید از ابزارهای ثالث که به ابزارهای obfuscator (یک نمونه سورس باز ) معروف هستند استفاده کنید تا با کمی پیچیدگی در متادیتاها، این مشکل را تا حدی برطرف کنند. ولی این ابزارها خیلی کامل نیستند، چرا که نباید به کامپایل کردن کار لطمه بزنند. پس اگر باز خیلی نگران این مورد هستید می‌توانید الگوریتم‌های حساس و اساسی خود را در قالب unmanaged code ارائه کنید که در بالا اشاراتی به آن کرده‌ایم.
برنامه‌های تحت وب به دلیل عدم دسترسی دیگران از امنیت کاملتری برخوردار هستند.
نظرات مطالب
روش اتصال دومین‌های ir. به یک DNS Server
با در نظر گرفتن طرح ابر ایران یا یا بهتر بگم همون اینترنت ملی سابق امکان اختلال در سرویس‌های خارجی وجود داره شما که همه چیز رو منتقل کردید به داخل شاید بهتر باشه از سرویس DNS داخلی استفاده کنید تا از مشکلات DNS احتمالی در آینده هم در امان باشیم. مشابه همین سرویس رو ابرآروان هم به صورت رایگان ارائه میده
در مورد قیمت‌های IR هم جالبه بدونید اگر از سایت‌های هاستینگ داخلی خرید کنید هزینه یکسال 5900 تومان و برای پنج سال 14600 تومان محاسبه می‌کنند. 
نظرات مطالب
صفحه بندی و مرتب سازی خودکار اطلاعات به کمک jqGrid در ASP.NET MVC
باسلام؛ من در قسمت نحوه ارتباط پایگاه داده با jqgrid مشکل دارم. در asp میامدیم DataSource گرید را مساوی با DataTable  قرار میدادیم ولی الان نمیدونم چه جوری داده‌های داخل پایگاه داده رو داخل jqGrid قرار بدم یا داده جدیدی از طریق jqgrid به پایگاه داده اضافه کنم. داده‌های من که حاصل اجرای   storeProcedure   است.  داخل یک datatable  قرار داره چه جوری میتونم jqgrid رو با اون ارتباط بدهم؟ تا داده‌های من رو نشون بده. ممنون میشم راهنماییم کنید.
مطالب
بررسی داده کاوی و OLAP

بررسی OLAP

واژه OLAP در اوایل سال‌‌های 1990 شکل گرفت. E.F.Codd بنیانگذار مدل داده‌ی رابطه‌ای، این واژه را در فرهنگ نامه کاربران بانک‌های اطلاعاتی توصیف نمود.
مشابه یک بانک اطلاعاتی رابطه‌ای که شامل تعدادی جدول می‌باشد، یک بانک اطلاعاتی OLAP شامل تعدادی Cube است. هر Cube مجموعه ای از Dimension‌ها و Measure هاست. Dimension یک شیء تحلیلی است که محور‌های مختصات را برای پرسش‌های تحلیلی تعریف می‌کند و از Member هایی تشکیل شده است که Member هر Dimension در قالب سلسله مراتب می‌تواند تعریف شود؛ در حالیکه Measure یک مقدار عددی است که در مختصات Cube تعریف می‌شود که این مقادیر از جداول تراکنشی بدست می‌آید (جدول Fact) که جزئیات هر رکورد تراکنشی در آنها ذخیره می‌شود. Measure‌ها حاوی اطلاعاتی هستند که از پیش، محاسبات تجمیعی بر روی آنها براساس سلسله مراتب تعریف شده در Dimension انجام شده است.
ساختار OLAP شبیه به یک مکعب روبیک از داده‌ها است که می‌توان آنرا در جهات مختلف چرخانید تا بتوان سناریو‌های «قبلا چه شده» و «چه می‌شد اگر ...» را بررسی نمود. مدل چند بعدی OLAP طریقه نمایش دادن داده‌ها را در مقایسه با بانک‌های اطلاعاتی رابطه‌ای تسهیل می‌کند. غالبا OLAP داده‌ها را از یک انباره داده استخراج می‌کند.

ابزارهای OLAP را به چند دسته تقسیم می‌کنند:


OLAP رو میزی:

ابزارهای ساده و مستقل که روی کامپیوتر‌های شخصی نصب شده و مکعب‌های کوچکی می‌سازند و آنها را نیز بر روی سیستم به شکل فایل ذخیره می‌کنند. بیشتر این ابزارها با صفحات گسترده ای نظیر Excel کار می‌کنند. به این ترتیب کسانی که در سفر هستند قادر به استفاده از این دسته از محصولات هستند. (در حال حاضر Web OLAP در حال جایگزین کردن این محصولات است)

MOLAP:

بجای ذخیره کردن اطلاعات در رکورد‌های کلید دار، این دسته از ابزارها، بانک‌های اطلاعاتی خاصی را برای خود طراحی کرده‌اند؛ بطوری که داده‌ها را به شکل آرایه‌های مرتب شده بر اساس ابعاد داده ذخیره می‌کنند. در حال حاضر نیز دو استاندارد برای این نوع ابزار وجود دارد. سرعت این ابزار بالا و سایز بانک اطلاعاتی آن نسبتا کوچک است.

ROLAP:

این ابزار‌ها با ایجاد یک بستر روی بانک‌های رابطه‌ای اطلاعات را ذخیره و بازیابی می‌کنند. بطوری که اساس بهینه سازی برخی بانک‌های مانند Red Brick ،MicreoStrategy و ... بر همین اساس استوار است. اندازه بانک اطلاعاتی این ابزار قابل توجه می‌باشد.

HOLAP:

در اینجا منظور از hybrid ترکیبی از MOLAP و ROLAP است. ابزار دارای بانک اطلاعاتی بزرگ و راندمان بالاتر نسبت به ROLAP می‌باشد.

مقایسه گزینه‌های ذخیره سازی در OLAP:


MOLAP:

این نوع ذخیره‌سازی بیشترین کاربرد در ذخیره اطلاعات را دارد. همچنین به صورت پیش فرض جهت ذخیره‌سازی اطلاعات انتخاب شده است. در این نوع تنها زمانی داده‌های منتقل شده به Cube به روز می‌شوند که Cube پردازش شود و این امر باعث تاخیر بالا در پردازش و انتقال داده‌ها می‌شود.

ROLAP:

 در ذخیره‌سازی ROLAP زمان انتقال بالا نیست که از مزایای این نوع ذخیره‌سازی نسبت به MOLAP است. در ROLAP اطلاعات و پیش‌محاسبه‌ها در یک حالت رابطه‌ای ذخیره می‌شوند و این به معنای زمان انتقال نزدیک به صفر میان منبع داده (بانک اطلاعاتی رابطه‌ای) و Cube می‌باشد. از معایب این روش می‌توان به کارایی پایین آن اشاره کرد زیرا زمان پاسخ برای پرس‌و‌جوهای اجرا شده توسط کاربران طولانی است. دلیل این کارایی پایین بکار نبردن تکنیک‌های ذخیره‌سازی چند بعدی است. 

HOLAP:

این نوع ذخیره‌سازی چیزی مابین دو حالت قبلی است. ذخیره اطلاعات با روش ROLAP انجام می‌شود، بنابراین زمان انتقال تقزیبا صفر است. از طرفی برای بالابردن کارایی، پیش‌محاسبه‌ها به صورت MOLAP انجام می‌گیرد در این حالت SSAS آماده است تا تغییری در اطلاعات مبداء رخ دهد و زمانی که تغییرات را ثبت کرد نوبت به پردازش مجدد پیش‌محاسبه‌ها می‌شود. با این نوع ذخیره‌سازی زمان انتقال داده‌ها به Cube را نزدیک به صفر و زمان پاسخ برای اجرای کوئری‌های کاربر را زمانی بین نوع ROLAP و MOLAP می‌رسانیم.
این سه روش ذخیره‌سازی انعطاف‌پذیری مورد نیاز را برای اجرای پروژه فراهم می‌کند. انتخاب هر یک از این روش‌ها به نوع پروژه، حجم داده‌ها و ... بستگی دارد.  در پایان می‌توان نتیجه گرفت که بهتر است زمان پردازش طولانی‌تری داشته باشیم تا اینکه کاربر نهایی در هنگام ایجاد گزارشات زمان زیادی را منتظر بماند.
 

بررسی داده کاوی

حجم زیاد اطلاعات، مدیران مجموعه‌ها را در تحلیل و یافتن اطلاعات مفید دچار چالش کرده است. داده کاوی، ابزار مناسب برای تجزیه و تحلیل اطلاعات و کشف و استخراج روابط پنهان در مجموعه‌های داده‌ای سنگین را فراهم می‌کند. گروه مشاوره‌ای گارتنر داده کاوی را استخراج نیمه اتوماتیک الگوها، تغییرات، وابستگی‌ها، نابهنجاری‌ها و دیگر ساختارهای معنی دار آماری از پایگاه‌های بزرگ داده تعریف می‌کند. داده کاوی، تلاشی برای یافتن قوانین، الگوها و یا میل احتمالی داده به مُدلی، در بین انبوهی از داده‌‌ها است.
داده کاوی فرآیندی پیچیده جهت شناسایی الگوها و مدل‌های صحیح، جدید و به صورت بالقوه مفید، در حجم وسیعی از داده می‌باشد؛ به طریقی که این الگو‌ها و مدلها برای انسانها قابل درک باشند. داده کاوی به صورت یک محصول قابل خریداری نمی‌باشد، بلکه یک رشته علمی و فرآیندی است که بایستی به صورت یک پروژه پیاده سازی شود.
به بیانی دیگر داده کاوی، فرآیند کشف الگوهای پنهان، جالب توجه، غیر منتظره و با ارزش از داخل مجموعه وسیعی از داده‌هاست و فعالیتی در ارتباط با تحلیل دقیق داده‌های سنگین بی ساختار است که علم آمار ناتوان از تحلیل آنهاست. بعضی مواقع دانش کشف شده توسط داده کاوی عجیب به نظر می‌رسد؛ مثلا ارتباط افراد دارای کارت اعتباری و جنسیت با داشتن دفترچه تامین اجتماعی یا سن، جنسیت و درآمد اشخاص با پیش بینی خوش حسابی او در بازپرداخت اقساط وام. داده کاوی در حوزه‌های تصمیم گیری، پیش بینی، و تخمین مورد استفاده قرار می‌گیرد.

پایه و اساس این تکنیک، ریشه در علوم زیر دارد:

        • علم آمار و احتمال
        • کامپیوتر (تکنولوژی اطلاعات)
        • هوش مصنوعی (تکنیکهای یادگیری ماشین)

ارتباط داده  کاوی و OLAP

OLAP و داده کاوی فن آوری‌های تحلیلی در خانواده BI به شمار می‌آیند. OLAP در زمینه تجمیع مقادیر عظیم داده‌های تراکنشی بر پایه تعاریف ابعادی مناسب است.

سوالات موضوعی که در ادامه به آن اشاره می‌شود توسط OLAP پاسخ داده  می‌شوند:

        • مقدار فروش کل تولیدات در سه ماهه گذشته در یک منطقه بخصوص چقدر بوده است؟

        • کدامیک از محصولات جزء ده محصول پر فروش تمامی فروشگاه‌ها در ماه گذشته بودند؟

        • کدامیک از محصولات برای مشتریان زن و مشتریان مرد فروش قابل توجهی داشته است؟

        • تفاوت میزان فروش روزانه در هنگام تبلیغات در مقایسه با دوره زمانی عادی چیست؟

فن آوری OLAP بر پایه محاسبات تجمیعی است. سرویس دهنده OLAP نوع خاصی از سرویس دهنده‌ی بانک اطلاعاتی محسوب می‌گردد که با داده‌های چند بعدی سروکار دارد. بسیاری از مشکلات و مخاطرات نظیر ایندکس گذاری، ذخیره سازی داده‌ها و ... که در RDBMS‌ها وجود دارد در سرویس دهنده‌ی OLAP نیز وجود دارد.
داده کاوی در یافتن الگو‌های پنهان از یک مجموعه داده توسط تحلیل همبستگی میان مقادیر مشخصه‌ها مناسب است.

تکنیک‌های داده کاوی دو گونه هستند: نظارت شده  و نظارت نشده. در داده کاوی نظارت شده کاربر می‌بایست مشخصه‌ی هدف و مجموعه داده‌ی ورودی را تعیین نماید. الگوریتم‌های داده کاوی نظارت شده شامل درخت تصمیم، نیو بیز و شبکه‌های عصبی هستند. تکنیک‌های داده کاوی نظارت نشده نیازی به تعیین مشخصه‌ی قابل پیش بینی ندارد. خوشه بندی مثال خوبی از داده کاوی نظارت نشده می‌باشد و به گروه بندی نقاط داده ای ناهمگن به زیر گروه هایی می‌پردازد که در آنها نقاط داده ای کم و بیش مشابه و همگن هستند.

در زیر نمونه ای از سوالات پاسخ داده شده توسط داده کاوی ارائه شده است:

        • مشخصات مشتریانی که تمایل به خرید جدیدترین مدل را دارند، چیست؟

        • چه کالاهایی باید به این دسته از مشتریان خاص توصیه و پیشنهاد گردد؟

        • برآورد میزان فروش مدلی خاص در سه ماهه آینده چیست؟

        • چگونه باید مشتریان را تقسیم بندی کرد؟


یکی از فرآیند‌های اصلی داده کاوی، تحلیل همبستگی میان مشخصه‌ها و مقادیر آنها است. محققین آمار در این موارد قرن‌ها مطالعه داشته‌اند. OLAP و داده کاوی دو فن آوری مختلف هستند اما فعالیت‌های یکدیگر را تکمیل می‌کنند. OLAP فعالیت هایی نظیر خلاصه سازی، تحلیل تغییرات در طول زمان و تحلیل‌های What If  را پشتیبانی می‌نماید. همچنین می‌توان آنرا برای تحلیل نتایج داده کاوی در سطوح مختلف و مجزا استفاده کرد. داده کاوی نیز می‌تواند در ساخت Cube‌های مفید‌تر سودمند باشد.

تفاوت میان OLAP و داده کاوی ارتباطی به تفاوت میان داده‌های تلخیص شده و داده‌های تشریحی ندارد. در واقع تمایز قابل توجهی میان مدل سازی توصیفی و تشریحی وجود دارد. توابع و الگوریتم هایی که معمولاً در ابزار‌های OLAP یافت می‌شود، توابع مدل سازی توصیفی به شمار  می‌آیند. در حالیکه توابعی که در آنچه که اصطلاحاً بسته داده کاوی نامیده می‌شود، یافت می‌شود توابع یا الگو‌های مدل سازی تشریحی هستند.
 

الگوریتم‌های داده کاوی موجود در SSAS و زمینه کاری متناظر

این الگوریتم‌ها را به 5 دسته تقسیم می‌توان نمود:

پیش بینی توالی وقایع

برای مثال جهت تجزیه و تحلیل مجموعه ای از شرایط آب و هوایی که منجر به وقوع پدیده خاصی می‌شود. از الگوریتم زیر استفاده می‌شود:

Microsoft Sequence Clustering Algorithm

یافتن گروهی از موارد مشترک در تراکنش ها

معروفترین مثال در خصوص تجزیه و تحلیل سبد بازار است. از الگوریتم‌های زیر استفاده می‌شود:
Microsoft Association Algorithm
Microsoft Decision Trees Algorithm

یافتن گروهی از موارد مشابه

معمول‌ترین کاربرد زمینه بخش بندی داده‌های مشتریان به منظور یافتن گروه‌های مجزا از مشتریان است. از الگوریتم‌های زیر استفاده می‌شود:
Microsoft Clustering Algorithm
Microsoft Sequence Clustering Algorithm

پیش بینی صفات گسسته

به عنوان مثال، پیش بینی اینکه یک مشتری خاص، تمایلی به خرید محصول جدید دارد یا خیر. از الگوریتم‌های زیر استفاده می‌شود:
Microsoft Decision Trees Algorithm
Microsoft Naive Bayes Algorithm
Microsoft Clustering Algorithm
Microsoft Neural Network Algorithm

پیش بینی صفات پیوسته

پیش بینی درآمد در ماه آینده مثالی از آن می‌باشد. از الگوریتم‌های زیر استفاده می‌شود:
Microsoft Decision Trees Algorithm
Microsoft Time Series Algorithm

نظرات مطالب
EF Code First #12
- من هر نوع طراحی رو تائید نمی‌کنم. چرا یک برنامه باید چندین DbContext داشته باشد؟ نیازی نداره. چرا باید چندین ماژول کنترلر داشته باشه؟ 
- سؤال شما خارج از موضوع بحث است (در اینجا بحثی در مورد طراحی «افزونه پذیر» مطرح نشده). برای طراحی افزونه پذیر می‌تونید به مباحث زیر مراجعه کنید:
ابتدا فقط و فقط یک DbContext مرکزی را در کل برنامه تعریف کنید. بعد تنظیمات نگاشت‌ها را به صورت پویا یافته و به آن اضافه کنید. سپس موجودیت‌های مهیا را به صورت پویا یافته و به Context مرکزی اضافه نمائید.
+ در EF نمی‌تونید در عمل چندین DbContext داشته باشید مرتبط با یک دیتابیس. Change tracking در EF بر مبنای یک DbContext کار می‌کند. اگر قرار باشد چندین وهله از DbContextهای مختلف مثلا در طی یک درخواست وجود داشته باشند، یعنی چندین اتصال باز شده به دیتابیس و چندین تراکنش مجزا در حال انجام است (کل بحث جاری از ابتدا). به علاوه قابلیت کار کردن با چندین موجودیت را به صورت همزمان در طی یک تراکنش از دست می‌دهید.
- برای اینکه در حین کار با Structure Map خطای Circular dependency را مشاهده نکنید، نیاز است یک کتابخانه یا حتی یک کلاس واسط طراحی کنید تا مشترکات در آن قرار گیرند.
نظرات مطالب
آموزش MDX Query - قسمت ششم – شروع کار با دستورات MDX
آقای علاقه مند :
در خصوص سوال اول شما (ستون‌ها یا سطرها در Range‌های مختلف گروه بندی شوند  ) این کار را باید با طراحی مناسب جداول Fact,Dimension در DW انجام دهید. به عبارت دیگر جدول Fact در خصوص آمار داشته باشید که یکی از فیلد‌های آن مشاهده تلویزیون می‌باشد و دو عدد Dimension که یکی گروه‌های سنی و دیگری ساعات می‌باشد.
حال باید در ETL واکشی مناسبی برای پر کردن جدول Fact داشته باشد.
در خصوص تبدیل MDX Query به T/SQL اطلاع دقیقی ندارم و با قاطعیت نمی‌توانم بگویم نه. اما استدلال بنده این می‌باشد که از آنجایی که MDX Query‌ها روی پایگاه داده‌ی MDB نوشته می‌شوند کاملا متفاوت از T\SQL می‌باشند که روی مدل رابطه ای کار می‌کند بنابر این تصور می‌کنم چنین امکانی نباشد و درضمن در جستجوی وب هم چیزی نیافتم.
در خصوص نمایش نهایی این چنین گزارشاتی چندین روش وجود دارد
  1. واکشی اطلاعات در Excel
  2. استفاده از Performance Point Service در Sharepoint (ترجیحا 2013)
  3. استفاده از کامپوننت‌های OLAP در محیط Visual Studio مانند RadarSoft,Dundas,...
  4. استفاده از نرم افزار هایی که کارشان ساختن گزارشات از MDB‌ها می‌باشد (CubeWare)
مطالب
React 16x - قسمت 26 - احراز هویت و اعتبارسنجی کاربران - بخش 1 - ثبت نام و ورود به سیستم
می‌خواهیم به برنامه‌ی لیست فیلم‌هایی که تا این قسمت تکمیل کردیم، امکانات جدیدی را مانند ورود به سیستم، خروج از آن، کار با JWT، فراخوانی منابع محافظت شده‌ی سمت سرور، نمایش و یا مخفی کردن المان‌های صفحه بر اساس سطوح دسترسی کاربر و همچنین محافظت از مسیرهای مختلف تعریف شده‌ی در برنامه، اضافه کنیم.
برای قسمت backend، از همان برنامه‌ی تکمیل شده‌ی قسمت قبل استفاده می‌کنیم که به آن تولید مقدماتی JWTها نیز اضافه شده‌است. البته این سری، مستقل از قسمت سمت سرور آن تهیه خواهد شد و صرفا در حد دریافت توکن از سرور و یا ارسال مشخصات کاربر جهت لاگین، نیاز بیشتری به قسمت سمت سرور آن ندارد و تاکید آن بر روی مباحث سمت کلاینت React است. بنابراین اینکه چگونه این توکن را تولید می‌کنید، در اینجا اهمیتی ندارد و کلیات آن با تمام روش‌های پیاده سازی سمت سرور سازگار است (و مختص به فناوری خاصی نیست). پیشنیاز درک کدهای سمت سرور قسمت JWT آن، مطالب زیر هستند:
  1. «معرفی JSON Web Token»
  2. «اعتبارسنجی مبتنی بر JWT در ASP.NET Core 2.0 بدون استفاده از سیستم Identity» 
  3. «پیاده سازی JSON Web Token با ASP.NET Web API 2.x»
  4. « آزمایش Web APIs توسط Postman - قسمت ششم - اعتبارسنجی مبتنی بر JWT»  


ثبت یک کاربر جدید

فرم ثبت نام کاربران را در قسمت 21 این سری، در فایل src\components\registerForm.jsx، ایجاد و تکمیل کردیم. البته این فرم هنوز به backend server متصل نیست. برای کار با آن هم نیاز است شیءای را با ساختار زیر که ذکر سه خاصیت اول آن اجباری است، به endpoint ای با آدرس https://localhost:5001/api/Users به صورت یک HTTP Post ارسال کنیم:
{
  "name": "string",
  "email": "string",
  "password": "string",
  "isAdmin": true,
  "id": 0
}
در سمت سرور هم در Services\UsersDataSource.cs که در انتهای بحث می‌توانید پروژه‌ی کامل آن‌را دریافت کنید، منحصربفرد بودن ایمیل وارد شده بررسی می‌شود و اگر یک رکورد دو بار ثبت شود، یک BadRequest را به همراه پیام خطایی، بازگشت می‌دهد.

اکنون نوبت به اتصال کامپوننت registerForm.jsx، به سرویس backend است. تا اینجا دو سرویس src\services\genreService.js و src\services\movieService.js را در قسمت قبل، به برنامه جهت کار کردن با endpoint‌های backend server، اضافه کردیم. شبیه به همین روش را برای کار با سرویس سمت سرور api/Users نیز در پیش می‌گیریم. بنابراین فایل جدید src\services\userService.js را با محتوای زیر، به برنامه‌ی frontend اضافه می‌کنیم:
import http from "./httpService";
import { apiUrl } from "../config.json";

const apiEndpoint = apiUrl + "/users";

export function register(user) {
  return http.post(apiEndpoint, {
    email: user.username,
    password: user.password,
    name: user.name
  });
}
توسط متد register این سرویس می‌توانیم شیء user را با سه خاصیت مشخص شده، از طریق HTTP Post، به آدرس api/Users ارسال کنیم. خروجی این متد نیز یک Promise است. در این سرویس، تمام متدهایی که قرار است با این endpoint سمت سرور کار کنند، مانند ثبت، حذف، دریافت اطلاعات و غیره، تعریف خواهند شد.
اطلاعات شیء user ای که در اینجا دریافت می‌شود، از خاصیت data کامپوننت RegisterForm تامین می‌گردد:
class RegisterForm extends Form {
  state = {
    data: { username: "", password: "", name: "" },
    errors: {}
  };
البته اگر دقت کرده باشید، در شیء منتسب به خاصیت data، خاصیتی به نام username تعریف شده‌است، اما در سمت سرور، نیاز است خاصیتی با نام Name را دریافت کنیم. یک چنین نگاشتی در داخل متد register سرویس کاربر، قابل مشاهده‌‌است. در غیراینصورت می‌شد در متد http.post، کل شیء user را به عنوان پارامتر دوم، درنظر گرفت و ارسال کرد.

پس از تعریف userService.js، به registerForm.jsx بازگشته و ابتدا امکانات آن‌را import می‌کنیم:
import * as userService from "../services/userService";
می‌شد این سطر را به صورت زیر نیز نوشت، تا تنها یک متد از ماژول userService را دریافت کنیم:
import { register } userService from "../services/userService";
اما روش as userService * به معنای import تمام متدهای این ماژول است. به این ترتیب نام ذکر شده‌ی پس از as، به عنوان شیءای که می‌توان توسط آن به این متدها دسترسی یافت، قابل استفاده می‌شود؛ مانند فراخوانی متد userService.register. اکنون می‌توان متد doSubmit این فرم را به سرور متصل کرد:
  doSubmit = async () => {
    try {
      await userService.register(this.state.data);
    } catch (ex) {
      if (ex.response && ex.response.status === 400) {
        const errors = { ...this.state.errors }; // clone an object
        errors.username = ex.response.data;
        this.setState({ errors });
      }
    }
  };


مدیریت و نمایش خطاهای دریافتی از سمت سرور

در این حالت برای ارسال اطلاعات یک کاربر، در بار اول، یک چنین خروجی را از سمت سرور می‌توان شاهد بود که id جدیدی را به این رکورد نسبت داده‌است:


اگر مجددا همین رکورد را به سمت سرور ارسال کنیم، اینبار خطای زیر را دریافت خواهیم کرد:


که از نوع 400 یا همان BadRequest است:


بنابراین نیاز است بدنه‌ی response را در یک چنین مواردی که خطایی از سمت سرور صادر می‌شود، دریافت کرده و با به روز رسانی خاصیت errors در state فرم (همان قسمت بدنه‌ی catch کدهای فوق)، سبب درج و نمایش خودکار این خطا شویم:


پیشتر در قسمت بررسی «کار با فرم‌ها» آموختیم که برای مدیریت خطاهای پیش بینی شده‌ی دریافتی از سمت سرور، نیاز است قطعه کدهای مرتبط با سرویس http را در بدنه‌ی try/catch‌ها محصور کنیم. برای مثال در اینجا اگر ایمیل شخصی تکراری وارد شود، سرویس یک return BadRequest("Can't create the requested record.") را بازگشت می‌دهد که در اینجا status code معادل BadRequest، همان 400 است. بنابراین انتظار داریم که خطای 400 را از سمت سرور، تحت شرایط خاصی دریافت کنیم. به همین دلیل است که در اینجا تنها مدیریت status code=400 را در بدنه‌ی catch نوشته شده ملاحظه می‌کنید.
سپس برای نمایش آن، نیاز است خاصیت متناظری را که این خطا به آن مرتبط می‌شود، با پیام دریافت شده‌ی از سمت سرور، مقدار دهی کنیم که در اینجا می‌دانیم مرتبط با username است. به همین جهت سطر errors.username = ex.response.data، کار انتساب بدنه‌ی response را به خاصیت جدید errors.username انجام می‌دهد. در این حالت اگر به کمک متد setState، کار به روز رسانی خاصیت errors موجود در state را انجام دهیم، رندر مجدد فرم، در صف انجام قرار گرفته و در رندر بعدی آن، پیام موجود در errors.username، نمایش داده می‌شود.


پیاده سازی ورود به سیستم

فرم ورود به سیستم را در قسمت 18 این سری، در فایل src\components\loginForm.jsx، ایجاد و تکمیل کردیم که این فرم نیز هنوز به backend server متصل نیست. برای کار با آن نیاز است شیءای را با ساختار زیر که ذکر هر دو خاصیت آن اجباری است، به endpoint ای با آدرس https://localhost:5001/api/Auth/Login به صورت یک HTTP Post ارسال کنیم:
{
  "email": "string",
  "password": "string"
}
با ارسال این اطلاعات به سمت سرور، درخواست Login انجام می‌شود. سرور نیز در صورت تعیین اعتبار موفقیت آمیز کاربر، به صورت زیر، یک JSON Web token را بازگشت می‌دهد:
var jwt = _tokenFactoryService.CreateAccessToken(user);
return Ok(new { access_token = jwt });
یعنی بدنه‌ی response رسیده‌ی از سمت سرور، دارای یک شیء JSON خواهد بود که خاصیت access_token آن، حاوی JSON Web token متعلق به کاربر جاری لاگین شده‌است. در آینده اگر این کاربر نیاز به دسترسی به یک api endpoint محافظت شده‌ای را در سمت سرور داشته باشد، باید این token را نیز به همراه درخواست خود ارسال کند تا پس از تعیین اعتبار آن توسط سرور، مجوز دسترسی به منبع درخواستی برای او صادر شود.

در ادامه برای تعامل با منبع api/Auth/Login سمت سرور، ابتدا یک سرویس مختص آن‌را در فایل جدید src\services\authService.js، با محتوای زیر ایجاد می‌کنیم:
import { apiUrl } from "../config.json";
import http from "./httpService";

const apiEndpoint = apiUrl + "/auth";

export function login(email, password) {
  return http.post(apiEndpoint + "/login", { email, password });
}
متد login، کار ارسال ایمیل و کلمه‌ی عبور کاربر را به اکشن متد Login کنترلر Auth، انجام می‌دهد و خروجی آن یک Promise است. برای استفاده‌ی از آن به کامپوننت src\components\loginForm.jsx بازگشته و متد doSubmit آن‌را به صورت زیر تکمیل می‌کنیم:
import * as auth from "../services/authService";

class LoginForm extends Form {
  state = {
    data: { username: "", password: "" },
    errors: {}
  };

  // ...

  doSubmit = async () => {
    try {
      const { data } = this.state;
      const {
        data: { access_token }
      } = await auth.login(data.username, data.password);
      console.log("JWT", access_token);
      localStorage.setItem("token", access_token);
      this.props.history.push("/");
    } catch (ex) {
      if (ex.response && ex.response.status === 400) {
        const errors = { ...this.state.errors };
        errors.username = ex.response.data;
        this.setState({ errors });
      }
    }
  };
توضیحات:
- ابتدا تمام خروجی‌های ماژول authService را با نام شیء auth دریافت کرده‌ایم.
- سپس در متد doSubmit، اطلاعات خاصیت data موجود در state را که معادل فیلدهای فرم لاگین هستند، به متد auth.login برای انجام لاگین سمت سرور، ارسال کرده‌ایم. این متد چون یک Promise را باز می‌گرداند، باید await شود و پس از آن متد جاری نیز باید به صورت async معرفی گردد.
- همانطور که عنوان شد، خروجی نهایی متد auth.login، یک شیء JSON دارای خاصیت access_token است که در اینجا از خاصیت data خروجی نهایی دریافت شده‌است.
- سپس نیاز است برای استفاده‌های آتی، این token دریافتی از سرور را در جایی ذخیره کرد. یکی از مکان‌های متداول اینکار، local storage مرورگرها است (اطلاعات بیشتر).
- در آخر کاربر را توسط شیء history سیستم مسیریابی برنامه، به صفحه‌ی اصلی آن هدایت می‌کنیم.
- در اینجا قسمت catch نیز ذکر شده‌است تا خطاهای حاصل از return BadRequestهای دریافتی از سمت سرور را بتوان ذیل فیلد نام کاربری نمایش داد. روش کار آن، دقیقا همانند روشی است که برای فرم ثبت یک کاربر جدید استفاده کردیم.

اکنون اگر برنامه را ذخیره کرده و اجرا کنیم، توکن دریافتی، در کنسول توسعه دهندگان مرورگر لاگ شده و سپس کاربر به صفحه‌ی اصلی برنامه هدایت می‌شود. همچنین این token ذخیره شده را می‌توان در ذیل قسمت application->storage آن نیز مشاهده کرد:



لاگین خودکار کاربر، پس از ثبت نام در سایت

پس از ثبت نام یک کاربر در سایت، بدنه‌ی response بازگشت داده شده‌ی از سمت سرور، همان شیء user است که اکنون Id او مشخص شده‌است. بنابراین اینبار جهت ارائه‌ی token از سمت سرور، بجای response body، از یک هدر سفارشی در فایل Controllers\UsersController.cs استفاده می‌کنیم (کدهای کامل آن در انتهای بحث پیوست شده‌است):
var jwt = _tokenFactoryService.CreateAccessToken(user);
this.Response.Headers.Add("x-auth-token", jwt);



در ادامه در کدهای سمت کلاینت src\components\registerForm.jsx، برای استخراج این هدر سفارشی، اگر شیء response دریافتی از سرور را لاگ کنیم:
const response = await userService.register(this.state.data);
console.log(response);
یک چنین خروجی را به همراه دارد که در آن، هدر سفارشی ما درج نشده‌است و فقط هدر content-type در آن مشخص است:


برای اینکه در کدهای سمت کلاینت بتوان این هدر سفارشی را خواند، نیاز است هدر مخصوص access-control-expose-headers را نیز به response اضافه کرد:
var jwt = _tokenFactoryService.CreateAccessToken(data);
this.Response.Headers.Add("x-auth-token", jwt);
this.Response.Headers.Add("access-control-expose-headers", "x-auth-token");
به این ترتیب وب سرور برنامه، هدر سفارشی را که قرار است برنامه‌ی کلاینت به آن دسترسی پیدا کند، مجاز اعلام می‌کند. اینبار اگر خروجی دریافتی از Axios را لاگ کنیم، در لیست هدرهای آن، هدر سفارشی x-auth-token نیز ظاهر می‌شود:


اکنون می‌توان این هدر سفارشی را در متد doSubmit کامپوننت RegisterForm، از طریق شیء response.headers خواند و در localStorage ذخیره کرد. سپس کاربر را توسط شیء history سیستم مسیریابی، به ریشه‌ی سایت هدایت نمود:
class RegisterForm extends Form {
  // ...

  doSubmit = async () => {
    try {
      const response = await userService.register(this.state.data);
      console.log(response);
      localStorage.setItem("token", response.headers["x-auth-token"]);
      this.props.history.push("/");
    } catch (ex) {
      if (ex.response && ex.response.status === 400) {
        const errors = { ...this.state.errors }; // clone an object
        errors.username = ex.response.data;
        this.setState({ errors });
      }
    }
  };

کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: sample-26-backend.zip و sample-26-frontend.zip
مطالب
آشنایی با ساختار IIS قسمت یازدهم
در این مطلب و همینطور مطلب بعدی قرار است به مبحث لاگ فایل‌ها Logfile بپردازیم. همانطور که می‌دانید سیستم IIS مثل هر سیستم دیگری لاگ هایی دارد که به مرور زمان این لاگ‌ها میتوانند مقدار زیادی از ظرفیت دیسک سخت را به خود اختصاص بدهند و این عمل میتواند موجب بروز مشکلاتی در سرور شود. به خوبی به یاد دارم که برای یکی از مشتریانم VPS تهیه نموده بودیم و بعد از یک سال با من تماس گرفت که سایت بالا نمی‌آید و وقتی بررسی شد، دیدم که از فضای دیسک سخت چند گیگابایتی، تنها چند مگابایت به طور ناچیز فضا برایش باقی مانده است و باعث شده است سرور از کار بیفتد. پس از بررسی متوجه شدیم تمام این فضاها توسط لاگ فایل‌ها پر شده است و از آنجا که سرویس دهنده تا مبلغی را به عنوان مدیریت سرور، ماهانه دریافت نکند، مدیریت این سرور مجازی را به عهده نداشته اند که البته بعدها با انتقال به یک سرور دیگر از یک سرویس دهنده دیگر مشکلات ما در مورد سرور برای همیشه حل شد.
پس این داستان به خوبی روشن می‌کند که مدیریت این لاگ‌ها چقدر میتواند مهم و حیاتی باشد. آقای تیم وَن از تیم تحریریه مایکروسافت در بخش IIS موارد زیر را برای مدیریت لاگ‌ها بر می‌شمارد:
  • فعال سازی فشرده سازی
  • انتقال لاگ‌ها به یک سیستم راه دور
  • حذف لاگ فایل‌های قدیمی از طریق اسکریپت نویسی
  • حذف لاگ فایل‌های قدیمی توسط IIS Log File Cleaner

فشرده سازی دایرکتوری لاگ فایل ها
مسیر ذخیره لاگ فایل‌ها در آدرس زیر می‌باشد. به این آدرس رفته و Properties دایرکتوری مورد نظر  را باز کنید و در برگه‌ی General آن، گزینه‌ی Advanced را زده تا در کادر جدیدی که باز می‌شود، گزینه‌ی Compress contents to save disk space را انتخاب کنید تا محتویات در هنگام ذخیره روی دیسک سخت فشرده شوند.
%SystemDrive%\inetpub\logs\LogFiles

این روش ساده‌ترین روش موجود برای مدیریت لاگ هاست ولی روش نهایی نیست و باز به مرور زمان این روش هم کارایی خودش را از دست خواهد داد. این روش بیشتر شبیه خرید زمان می‌باشد تا اینکه یک راه حل نهایی برای حل مشکل باشد. البته این را هم باید مدنظر داشت که موقع تیک زدن گزینه بالا عملیات فشرده سازی باعث کند شدن سرعت کامپیوتر در حین آغاز عمل ذخیره سازی لاگ فایل‌ها هم خواهد شد. پس اگر قصد چنین کاری ذا دارید در ساعاتی که سرور کمترین فشار از طرف کاربران را دارد یا اصطلاحا پیک کاری آن پایین است انجامش دهید.


انتقال لاگ فایل‌ها به یک سیستم راه دور

همانطور که در بالا اشاره کردیم محل پیش فرض ذخیره سازی لاگ‌ها درمسیر

%SystemDrive%\inetpub\logs\LogFiles

قرار دارد و این محل ذخیره سازی برای هر سرور یا حتی یک وب سایت خاص در صفحه تنظیمات Logging مشخص شده است و شما در میتوانید این لاگ‌ها را حتی برای کل سرور یا مربوط به یک سایت خاص، به سروری دیگر انتقال دهید. این امکان می‌تواند به امنیت سیستم هم کمک فراوانی کند تا اگر دیسک محلی Local Disk هم دچار مشکل شد، باز خواندن لاگ فایل‌ها میسر باشد و با استفاده از ابزارهای تحلیل لاگ فایل ها، آن‌ها را مورد بررسی قرار دهیم. برای تغییر محل ذخیره سازی لاگ‌ها به یک سیستم راه دور، راه حل زیر را طی کنید.

در IIS وب سایتی را که میخواهید لاگ آن انتقال یابد، انتخاب کنید؛ یا اگر لاگ کل سیستم IIS را میخواهید انتقال بدهید نام سرور را در لیست درختی انتخاب کنید و از ماژول‌های سمت راست، ماژول Logging را انتخاب کنید و در قسمت Directory که محل ذخیره سازی فعلی لاگ‌ها را نوشته شده است، به صورت UNC آدرس دهی کنید. در آدرس زیر اولی نام سرور است Contoso-server1\\ و دومی هم Logs نام پوشه‌ای که به اشتراک گذاشته شده است.


حذف لاگ فایل‌های قدیمی با استفاده از اسکریپت

با این روش میتوانید لاگ فایل هایی را که بعد از مدتی معین که دلخواه شما هست، از سیستم حذف نمایید و اگر این اسکریپت را زمان بندی خودکار نمایید، می‌توانید از مراقبت مداوم و ثابت این کار نیز رها شوید.

با ستفاده از VBScript بررسی می‌کنیم که اگر مثلا عمر لاگ فایل به 30 روز رسیده است، باید حذف شوند. خط دوم کد زیر نهایت عمر یک لاگ فایل را مشخص می‌کند:

sLogFolder = "c:\inetpub\logs\LogFiles"
iMaxAge = 30   'in days
Set objFSO = CreateObject("Scripting.FileSystemObject")
set colFolder = objFSO.GetFolder(sLogFolder)
For Each colSubfolder in colFolder.SubFolders
        Set objFolder = objFSO.GetFolder(colSubfolder.Path)
        Set colFiles = objFolder.Files
        For Each objFile in colFiles
                iFileAge = now-objFile.DateCreated
                if iFileAge > (iMaxAge+1)  then
                        objFSO.deletefile objFile, True
                end if
        Next
Next

اسکریپت بالا تمامی subfolder‌ها را برای همه سایت‌ها بررسی کرده و لاگ‌های آنان را حذف می‌کند. ولی اگر دوست دارید این عملیات را تنها به یک وب سایت محدود کنید، باید مسیر را در خط اول دقیق‌تر مشخص کنید.

برای اجرای دستی اسکریپت در cmd تایپ کنید:

cscript.exe c:\scripts\retentionscript.vbs

ولی اگر میخواهید این اسکریپت در هر دوره‌ی زمانی خاص اجرا شود، یا زمان بندی Scheduling گردد، دیگر مجبور نیستید هر بار به فکر نگهداری از لاگ‌ها باشید.


زمان بندی اجرای اسکریپت

server manager (قابل تست در ویندوزهای سرور)  را باز کرده و از منوی Tools گزینه Task Scheduler را انتخاب کنید و در قسمت Actions گزینه Create Task را انتخاب نمایید. در کادر باز شده نام "Delete Log Files " را برای مثال برگزینید و در قسمت Security هم کاربری که اجازه اجرای اسکریپت را دارد مشخص کنید.

برگه Triggers را انتخاب کرده و گزینه New را انتخاب کنید و عملیات زمان بندی را تنظیم کنید و حتما بعد از زمان بندی مطمئن باشید که تیک Enabled فعال است.

در برگه Actions هم گزینه New را انتخاب کنید؛ در کادر باز شده از لیست Start a program را انتخاب کرده و در قسمت Program\script، دستور cscript را ذکر نمایید و به عنوان آرگومان ورودی Add arguments  هم مسیر اسکریپت خود را ذکر نمایید و کادر را تایید کنید.

برای آغاز زمان بندی در لیست وظیفه‌های فعال active task pane، وظیفه ای که الان ساخته اید را اجرا کرده و به مسیر ذخیره لاگ‌ها رفته و می‌بینید که لاگ‌های مورد نظر حذف شده‌اند؛ پس از صحت اجرای اسکریپت مطمئن می‌شویم. دوباره به لیست وظایف رفته و گزینه End را بزنید تا وظیفه، در حالت Ready قرار گیرد تا از همین الان فرایند زمان بندی اجرای اسکریپت آغاز شود.


حذف لاگ فایل‌ها با استفاده از IIS Log Cleaner Tools

ساده‌ترین ابزار برای مدیریت حذف لاگ فایل هاست که هر یک ساعت یکبار اجرا شده و لاگ فایل‌های تاریخ گذشته را که زمانش را شما تعیین می‌کنید، به سمت سطل زباله که البته درستش بازیافت است Recycle Bin انتقال میدهد تا از ضرر از دست دادن لاگ‌ها جلوگیری کند که بعدا شما میتوانید آن‌ها را به صورت دستی حذف کنید. همچنین عملیات خودکار حذف را نیز می‌توان متوقف نمود.

ابتدا برنامه را از اینجا  دانلود کنید. موقعیکه برنامه را اجرا کنید، در نوتیفیکیشن taskbar می‌نشیند و برنامه با یک پیغام به شما اعلام می‌کند، این اولین بار است که برنامه را باز کرده‌اید. پس یک سر به setting آن بزنید؛ با انتخاب گزینه‌ی settings برنامه بسته شده و فایل Settings.txt برای شما باز می‌شود که مدت زمان عمر لاگ فایل و مسیر ذخیره آن‌ها، از شما پرسیده می‌شود که مقدار عمر هر لاگ فایل به طور پیش فرض 30 روز و مسیر ذخیره‌ی لاگ‌ها همان مسیر پیش فرض IIS است که اگر شما دستی آن را تغییر داده اید، با پرسیدن آن، از محل لاگ‌ها اطمینان کسب می‌کند. در صورتی که قصد تغییری را در فایل، دارید آن را تغییر داده و ذخیره کنید و برنامه را مجددا اجرا کنید.

نکات نهایی در مورد این برنامه :

  • اگر از ابزار IIS Cleaner Tool استفاده می‌کنید باید دستی سطل بازیافت را هم پاک کنید و هم اینکه میتوانید یک محدودیت حجمی برای Recycle Bin قرار دهید که اگر به یک حدی رسید، خودکار پاک کند تا مشکلی برای سیستم عامل ایجاد نشود که البته به طور پیش فرض چنین است.
  • برنامه بالا به طور پیش فرض ریشه‌ی لاگ‌ها را حذف می‌کند. پس اگر میخواهید فقط سایت خاصی را مد نظر داشته باشد، آدرس دایرکتوری آن را اضافه کنید. البته چون این برنامه فقط روی یک دایرکتوری کار می‌کند و شما چند وب سایت دارید و مثلا میخواهید سه تای آن‌ها را پاکسازی کنید، چاره‌ی جز استفاده از اسکریپت‌های با زمان بندی ندارید.
  • برنامه‌ی بالا فقط فایل هایی با پسوند log را به سطل بازیافت انتقال می‌دهد.
  • برنامه‌ی بالا یک سرویس نیست و باید به طور دستی توسط کاربر اجرا گردد. پس اگر ریست هم شد باید دستی اجرا شود یا آن را به داخل پوشه startup بکشید.
  • برنامه برای اجرایش نیاز به لاگین کاربر و مجوز نوشتن در آن پوشه را دارد تا به درستی کار کند.
در قسمت بعدی مبحث لاگ‌ها را ادامه خواهیم داد و با ماژول Logging در IIS و تنظیماتش آشنا خواهیم شد.
نظرات مطالب
نحوه استفاده از ViewModel در ASP.NET MVC
با تشکر از مطلب خوبتان
فقط یه سوال اینکه  View Model فقط در جاهایی مثل این که مثال زدید کاربرد دارد یا در جایی که الان در برنامه‌های وب انجام میدیم و چند تا جدول که با هم ارتباط دارند و یک view از روی آنها ایجاد می‌کنیم و در پروژه از این View ساخته شده استفاده می‌کنیم برای اعمال مختلف نیز می‌توان استفاده کرد . برای مثال دانشجو با نمرات و درس‌ها و رشته که با هم در ارتباط دارند را یک  View Model کرد و در هر قسمت پروژه که نیاز داشتیم از این استفاده کنیم؟
یه سوال دیگه هم اینکه خیلی جاها دیدم که نوشته از Model به صورت مستقیم استفاده نکنید و یک View Model  این وسط برای ارتباط داشته باشیم می‌خواستم ببینم آیا درسته و دلیلش چیه ؟

مطالب
رویدادها در jQuery
Jquery یکی از کتابخانه‌های قدرتمند JavaScript است که به طور وسیعی مورد استفاده طراحان وب قرار میگیرد. این کتابخانه از سه دیدگاه بسیار سودمند است؛ ابتدا به دلیل مدیریت قدرتمند Dom که دارد و دوم اینکه ارتباط Ajax را بسیار راحت کرده است و هم اینکه بستر پلاگین نویسی را فراهم ساخته است، به طوری که میلیون‌ها کتابخانه ثالث از روی همین کتابخانه ایجاد شده است. زمانیکه شما به مطالعه این کتابخانه رو آورید و نمونه کدهای مختلفی از آن را بر روی شبکه اینترنت ببینید، ممکن است این کتابخانه در عین سادگی که دارد، ابهاماتی را برای شما ایجاد کند که یکی از آن‌ها نحوه استفاده از رویدادهاست. لیست زیر نمونه‌ای از نحوه رویداد نویسی در جی کوئری است:
$().click(fn)
$().bind('click',fn)
$().live('click',fn)
$().delegate(selector, 'click', fn)
$().on('click',fn);
$().on('click', selector ,fn);
دو مورد اول در لیست، یکی هستند و در واقع مورد اول یک میانبر برای مورد دوم محسوب میشود و در پشت صحنه در واقع همان خط دوم مورد استفاده قرار میگیرد. از مزایایی که در مورد bind نسبت به استفاده مستقیم از اسم رویداد میتوان گفت این است که میتواند در یک زمان به چند رویداد متصل شود. به عنوان مثال کد زیر نمونه‌ای از آن است:
    $(".test").bind( "click mouseover mouseout", function() { console.log('fired!') } );
در خط بالا المان‌هایی که با کلاس test مزین گشته‌اند، به سه رویداد و یک تابع بایند یا متصل گشته‌اند. برای غیرفعال سازی این رویدادها میتوان از متد unbind استفاده کرد:
$(".test").unbind( "click");
برای استفاده از این دو حالت باید در نظر گرفت که تنها المان‌هایی به این رویداد متصل یا بایند میگردند که در زمان بررسی DOM، یعنی بارگذاری اولیه سایت وجود داشته‌اند و در صورتیکه المان جدیدی به صفحه اضافه شود یا اینکه جایگزین المان دیگری شود، بایند نخواهند شد و تنها المان‌های قدیمی کار خواهند کرد و در صورتیکه المانی از روی صفحه حذف شود، این اتصال از بین خواهد رفت.

مورد سوم، متد معروف live است که هم بر روی المان‌های قدیمی و هم بر روی المان‌های جدید جواب میدهد. ولی نکته‌ای که در مورد live وجود دارد این است که در نسخه‌های اخیر به دلیلی که در جلوتر عنوان میشود حذف شده است و دیگر وجود ندارد. دلیل این حذف هم این میباشد که در واقع متد live برای اینکه افزوده شدن المان‌های جدید را زیر نظر بگیرد، به خود المان متصل نمیشود؛ بلکه به به کل سند HTML یا بدنه وب سایت متصل میشد و کل ناحیه را مورد بررسی قرار میداد تا اگر المان جدیدی اضافه شد، بتواند رویداد مرتبطی را بر روی آن اجرا کند. همچنین در این حالت رویدادی‌هایی از این نوع، در اجداد این المان نیز اجرا میگردند. یعنی رویداد، از المان آغاز شده، سپس به سمت اجدادش انتقال خواهد یافت (به این حالت Bubbling up گفته میشود). پس برای اینکه این ناحیه کوچک‌تر و جزئی‌تر شود، متد دیگری جایگزین آن شد؛ به نام delegate:
$("#area").delegate('.test','click',function(e){...});

----------------------------------------
<div id="area">
<span>Span1</span>
<span>Span2</span>
</div>
این حالت که جایگزین حالت قبلی شده است بدین صورت است که ناحیه‌ای با آی دی area وجود دارد که المان‌هایی با کلاس test در آن قرار میگیرند. پس، از این به بعد، بجای اینکه کل سند بررسی شود، فقط همین بخش مورد بررسی قرار میگیرد و رویداد کلیک، بر روی المانی با کلاس test اجرا میشود و bubbling up کمتری خواهیم داشت و میتوان آن را کنترل کرد. برای حذف رویدادهای live از المان‌های مربوطه، میتوان از die و برای delegate از undelegate همانند unbind استفاده کرد. همچنین حالت استفاده از زنجیره‌ای از متدها در متد live در نظر نگرفته شده، ولی بعد از دلیگیت میتوان از متدهای دیگر، به صورت زنجیره‌ای استفاده کرد.

 از نسخه 1.7 به بعد  توصیه شده‌است به جای تمامی متدهای بالا،  از on استفاده شود که به مراتب کارآایی بهتری دارد و اکثر این متدهای بالا، حذف یا منسوخ شده اعلام گشته‌اند و احتمال حذف آن‌ها در نسخه آتی وجود دارد. به عنوان مثال delegate از نسخه 3 به بعد منسوخ اعلام شده‌است. نحوه صدا زدن on بجای دلیگیت به شکل زیر خواهد بود:
$("#area").on('click','.test',function(e){...});


نکته مهم : بعضی‌ها برای راحتی کار بدین شکل کار میکنند ولی این شیوه فرقی با متد live  ندارد.
$("body").on('click','.test',function(e){...});

در حالت Bubbling up این گونه است که اگر کدی به شکل زیر باشد و رویداد کلیک روی text هدف ما باشد، رویداد کلیک به سمت اجداد آن حرکت میکند. یعنی ابتدا رویداد کلیک b اجرا میشود، سپس a و سپس رویداد کلیک div اجرا میشود و الی آخر:
<div> <a> <b>text</b> </a> </div>
برای حل این مسئله و جلوگیری از این اتفاق میتوان از متد stopPropagation استفاده کرد که در حالت استفاده از متد on جواب میدهد؛ ولی در متد live، استفاده از آن بی فایده است. کد زیر را میتوانید با حالت‌های مختلف بررسی کرده و نتیجه این متد را در کنسول مرورگر خود ببینید:
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
    <script
  src="https://code.jquery.com/jquery-1.12.4.min.js"
  integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ="
  crossorigin="anonymous"></script>
        <script src="http://code.jquery.com/jquery-migrate-1.4.1.js"></script>
    <script>
    $(document).ready(function(){
      $(".myspan").on( "click",".test", function(e) {
        e.stopPropagation();
        console.log('test fired!') } );
      $(".myspan").on( "click", function() { console.log(' myspan fired!') } );
      $(".mydiv").on( "click", function() { console.log(' mydiv fired!') } );

    });
    </script>
  </head>
  <body>
<div class="mydiv">
  <span class="myspan">
    <button type="button" class="test">Ok</button>
  </span>

</div>
  </body>
</html>

نکته تکمیلی
اینکه در استفاده از دلیگیت و on میتوان رویدادها را به شکل زیر هم مورد استفاده قرار داد:
$().on({
    'click': function (e) {
       // function
    },
    'hover': function (e) {
       // function    
    }
});