نظرات مطالب
اعتبارسنجی مبتنی بر JWT در ASP.NET Core 2.0 بدون استفاده از سیستم Identity
- قسمت «cfg.TokenValidationParameters» در سمت سرور، کار بررسی امضای دیجیتال و سایر مشخصات امنیتی را انجام می‌دهد. بنابراین امکان دستکاری آن در سمت کاربر نیست. اگر دستکاری شود، امضای دیجیتال آن در سمت سرور برگشت می‌خورد و در قسمت cfg.Events لاگ خواهد شد.
- در حافظه‌ی سرور چیزی را نباید ذخیره کنید. سمت سرور برنامه‌های وب، stateless و یا بدون حالت است (یعنی قرار نیست در آن، پس از پایان درخواست، اطلاعاتی از کاربر در حافظه باقی بماند؛ بدلیل محدودیت منابع و مسایل امنیتی). اما این توکن‌ها در سمت کاربر عموما توسط روش local storage ذخیره می‌شوند و هربار از سرور واکشی نمی‌شوند. این توکن‌ها فقط هربار به ازای هر درخواست به منابع محافظت شده‌ی سمت سرور، «باید» از کلاینت به سمت سرور ارسال شوند. در غیراینصورت درخواست بدون توکن، یک درخواست معمولی اعتبارسنجی نشده‌است و ذخیره سازی اطلاعات در حافظه‌ی سرور عملا بی‌معنا است. اطلاعات بیشتر در مورد ذخیره سازی سمت کلاینت: «معرفی Local Storage و چند کتابخانه مرتبط» و «ذخیره سازی اطلاعات در مرورگر توسط برنامه‌های Angular»  
نظرات مطالب
روش از کار انداختن صفحه‌ی Add service reference در VS.NET
با درود و خسته نباشید
استاد گرامی پرسشی داشتم
ما در سازمانمان نرم افزاری داریم که کاربران آن در Active directory تعریف شده اند.
برنامه با وب سرویس در ارتباط است که در یک سروری قرار گرفته است که آن سرور با یک سرور دیگر از طریق کابل شبکه در ارتباط است.
سرور دوم سروری است که پایگاه داده روی آن قرار گرفته است.
با توجه به اینکه با WCF کاربر جاری برنامه را می توان به دست آورد؛ ما کاربر جاری را تا سطح سرور 1 می آوریم ولی برای ارسال آن به اس کیو ال دو راه حل داریم.
راهی که هم اکنون از آن استفاده می کنیم این است که Connection string مان تک کاربره است و دیگر اینکه هم اکنون که کاربر جاری را داریم همان را با Connection string به سمت SQL بفرستیم و که در نتیجه گزارش گیری و مانیتورینگ بسیار خوبی خواهیم داشت. ولی باید همه کاربران در SQL تعریف شوند چون سرور پایگاه داده به دومین متصل نیست.

به نظر شما در صورتی که سرورهای نسبتاً خوبی از لحاظ سخت افزاری داشته باشیم و کاربرانی در حدود 2000 نفر به طور کلی و 200 نفر همزمان داشته باشیم، Connection string تک کاربره بهتر است یا چند کاربره؟

با سپاس فراوان
مطالب
افزودن SQL Server CE 4.0 به لیست توزیع مجدد در InstallShield 2010
در برنامه‌ی ساخت نصاب InstallShield، در قسمت افزودن بسته‌های نصبی برای برنامه‌ی ساخته شده


بسته‌ی نصب  SQL Server CE 3.5 SP2 وجود دارد:


اما برای برنامه‌های جدیدتر نیاز به افزودن بسته‌ی نصب دیتابیس SQL Server CE نسخه 4 است که با عدم وجود این بسته روبرو هستیم. در ادامه با نحوه‌ی افزودن این بسته‌ها آشنا خواهید شد.

اینگونه بسته‌ها در کنار برنامه‌ی ساخت نصاب و در پوشه‌ی SetupPrerequisites نگهداری شده و با نوع *.prq ذخیره می‌شوند. این نوع فایل‌ها از نوع xml هستند و در واقع یک نوع کار نگاشت را انجام می‌دهند. برای نمونه محتویات یکی از این فایل‌ها را در زیر می‌بینید:
<?xml version="1.0" encoding="UTF-8"?>
<SetupPrereq>
<conditions>
<condition Type="32" Comparison="2" Path="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server Compact Edition\v3.5\ENU" FileName="DesktopRuntimeVersion" ReturnValue="3.5.8080.0"></condition>
</conditions>
<operatingsystemconditions>
<operatingsystemcondition MajorVersion="5" MinorVersion="0" PlatformId="2" CSDVersion="" ServicePackMajorMin="3"></operatingsystemcondition>
<operatingsystemcondition MajorVersion="5" MinorVersion="1" PlatformId="2" CSDVersion="" Bits="1" ProductType="1"></operatingsystemcondition>
<operatingsystemcondition MajorVersion="6" MinorVersion="0" PlatformId="2" CSDVersion="" Bits="1"></operatingsystemcondition>
<operatingsystemcondition MajorVersion="5" MinorVersion="2" PlatformId="2" CSDVersion="" Bits="1" ProductType="2|3"></operatingsystemcondition>
<operatingsystemcondition MajorVersion="6" MinorVersion="1" PlatformId="2" CSDVersion="" Bits="1"></operatingsystemcondition>
<operatingsystemcondition MajorVersion="6" MinorVersion="0" PlatformId="2" CSDVersion="" Bits="1" ProductType="2|3"></operatingsystemcondition>
</operatingsystemconditions>
<files>
<file LocalFile="&lt;ISProductFolder&gt;\SetupPrerequisites\SQL CE 3.5\SSCERuntime_x86-ENU.msi" URL="http://go.microsoft.com/fwlink/?LinkId=166085&amp;clcid=0x409" CheckSum="86AF6D36DFF214718DCD35D851249D3D" FileSize="0,3164160"></file>
</files>
<execute file="SSCERuntime_x86-ENU.msi" cmdline="/q /norestart" cmdlinesilent="/q /norestart" returncodetoreboot="1641,3010,4123" requiresmsiengine="1"></execute>
<properties Id="{A7C4B3C0-F3A0-426A-A043-E13DBA123E52}" Description="This prerequisite installs the Microsoft SQL Server Compact 3.5 SP2." AltPrqURL="http://saturn.installshield.com/is/prerequisites/microsoft sql ce 3.5 sp2.prq"></properties>
<behavior Reboot="2"></behavior>
</SetupPrereq>
کافیست به ازای هر نسخه‌ی 32 و یا 64 بیتی، فایل xml مورد نظر، با پسوند prq در پوشه‌ی SetupPrerequisites ذخیره شود.
برای نسخه 32 بیتی(Microsoft SQL CE 4.0 x86.prq ):
<?xml version="1.0" encoding="UTF-8"?>
<SetupPrereq>
    <conditions>
        <condition Type="32" Comparison="2" Path="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server Compact Edition\v4.0\ENU" FileName="DesktopRuntimeVersion" ReturnValue="4.0.8482.1"></condition>
    </conditions>
    <operatingsystemconditions>
        <operatingsystemcondition CSDVersion="" Bits="1"></operatingsystemcondition>
    </operatingsystemconditions>
    <files>
        <file LocalFile=".\SSCERuntime_x86-ENU.exe" URL="http://download.microsoft.com/download/0/5/D/05DCCDB5-57E0-4314-A016-874F228A8FAD/SSCERuntime_x86-ENU.exe" CheckSum="0A55733CF406FBD05DFCFF5A27A0B4F7" FileSize="0,2379544"></file>
    </files>
    <execute file="SSCERuntime_x86-ENU.exe"></execute>
    <properties Id="{2754916B-119B-4428-9F94-DC9E45072CCC}"></properties>
    <behavior Failure="4" Reboot="2"></behavior>
</SetupPrereq>
و برای نسخه 64 بیتی(Microsoft SQL CE 4.0 x64.prq) : 
<?xml version="1.0" encoding="UTF-8"?>
<SetupPrereq>
    <conditions>
        <condition Type="32" Comparison="2" Path="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server Compact Edition\v4.0\ENU" FileName="DesktopRuntimeVersion" ReturnValue="4.0.8482.1"></condition>
    </conditions>
    <operatingsystemconditions>
        <operatingsystemcondition CSDVersion="" Bits="2"></operatingsystemcondition>
    </operatingsystemconditions>
    <files>
        <file LocalFile=".\SSCERuntime_x64-ENU.exe" URL="http://download.microsoft.com/download/0/5/D/05DCCDB5-57E0-4314-A016-874F228A8FAD/SSCERuntime_x64-ENU.exe" CheckSum="A417082ECAEDD95AFB41F73DC140C350" FileSize="0,2621240"></file>
    </files>
    <execute file="SSCERuntime_x64-ENU.exe"></execute>
    <properties Id="{7CB7BE3C-614A-403F-94D9-5652285A3EDF}"></properties>
    <behavior Failure="4" Reboot="2"></behavior>
</SetupPrereq>
و در نهایت این دو بسته به لیست اضافه خواهد شد:



 
نظرات اشتراک‌ها
تبدیلگر ایران سیستم به یونیکد
مرسی با این کد کاملا صحیح کاراکترها تبدیل میشه. اما همچنان زمان آپلود فایل خطا میداد که مقدار فیلد شماره لیست در فایل بیمه شدگان صحیح نیست.
یک راه دیگه رو امتحان کردم که بالاخره جواب داد! در فولدر DataBase برنامه تامین اجتماعی دو فایل DSKKAR00  و DSKWOR00 دیدم که فیلدها در آن‌ها تعریف شده بود ولی دیتا براشون ثبت نشده، حدس زدم که برنامه تامین اجتماعی هم از همین فایل‌ها استفاده میکنه.
من در برنامه خودم کد مربوط به ایجاد فایل رو حذف و آدرس این فایل‌ها رو دادم که دیتا در این فایل‌ها Insert بشه و مشکل حل شد و سایت فایل‌های من رو قبول کرد !
فایل راهنمای تامین اجتماعی که ساختار جدول‌های این فایل‌ها رو نوشته بود اشتباه بوده و نوع فیلدهایی که در اون فایل گفته بود در برنامه خودشون استفاده نشده و در سایت تامین اجتماعی هم قبول نمی‌کرد! 
مطالب
آزمایش Web APIs توسط Postman - قسمت سوم - نکات تکمیلی ایجاد درخواست‌ها
تا اینجا، یک دید کلی را نسبت به postman و توانمندی‌های آن پیدا کرده‌ایم. در ادامه قصد داریم، تعدادی نکته‌ی تکمیلی مهم را که در حین ساخت درخواست‌ها در postman، به آن‌ها نیاز پیدا خواهیم کرد، بررسی کنیم.


ایجاد یک request bin جدید

برای مشاهده‌ی محتوای ارسالی توسط postman بدون برپایی وب سرویس خاصی، از سایت requestbin استفاده خواهیم کرد. در اینجا با کلیک بر روی دکمه‌ی create a request bin، یک آدرس موقتی را مانند http://requestbin.fullcontact.com/1gdduy21 برای شما تولید می‌کند. می‌توان انواع و اقسام درخواست‌ها را به این آدرس ارسال کرد و سپس با ریفرش کردن آن در مرورگر، دقیقا محتوای ارسالی به سمت سرور را بررسی نمود.
برای مثال اگر همین آدرس را در postman وارد کرده و سپس بر روی دکمه‌ی send آن کلیک کنیم، پس از ریفرش صفحه، چنین تصویری حاصل می‌شود:



Encoding کوئری استرینگ‌ها در postman

مثال زیر را درنظر بگیرید:


در اینجا با استفاده از گرید ساخت Query Params، دو کوئری استرینگ جدید را ایجاد کرده‌ایم که در دومی، مقدار وارد شده، دارای فاصله است. اگر این درخواست را ارسال کنیم، مشاهده خواهیم کرد که مقدار ارسالی توسط آن encoded نیست:


برای رفع این مشکل می‌توان بر روی تکست‌باکس ورود مقدار یک کلید، کلیک راست کرد و از منوی باز شده، گزینه‌ی encode URI component را انتخاب نمود:


البته برای اینکه این گزینه درست عمل کند، نیاز است یکبار کل متن را انتخاب کرد و سپس بر روی آن کلیک راست نمود، تا انتخاب گزینه‌ی encode URI component، به درستی اعمال شود:



امکان تعریف متغیرها در آدرس‌های HTTP

Postman از امکان تعریف path variables پشتیبانی می‌کند. برای مثال مسیر api.example.com/users/5/contracts/2 را در نظر بگیرید که می‌تواند سبب نمایش اطلاعات قرارداد دوم کاربر پنجم شود. برای پویا کردن یک چنین آدرسی در postman می‌توان از مسیری مانند api.example.com/users/:userid/contracts/:contractid استفاده کرد:


اگر به تصویر فوق دقت کنیم، متغیرهای شروع شده‌ی با :، در قسمت path variables ذکر شده‌اند و به سادگی قابل تغییر و مقدار دهی می‌باشند (در گریدی همانند گرید کوئری استرینگ‌ها) که برای آزمایش دستی، بسیار مفید هستند.


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

زمانیکه برای مثال، نوع درخواست به Post تغییر می‌کند، امکان تنظیم بدنه‌ی آن نیز مسیر می‌شود. در این حالت اگر گزینه‌ی form-data را انتخاب کنیم، با نزدیک کردن اشاره‌گر ماوس به هر ردیف جدید (پیش از ورود کلید آن ردیف)، می‌توان نوع Text و یا File را انتخاب کرد:


در اینجا پس از انتخاب گزینه‌ی File، می‌توان علاوه بر تعیین کلید این ردیف، با استفاده از دکمه‌ی select files، چندین فایل را نیز برای ارسال انتخاب کرد:



روش انتقال درخواست‌های پیچیده به Postman

تا اینجا روش ساخت درخواست‌های متداولی را بررسی کردیم که آنچنان پیچیده، طولانی و به همراه جزئیات زیادی (مانند کوکی‌ها،انواع و اقسام هدرها و ...) نبودند. فرض کنید می‌خواهید درخواست ارسال یک امتیاز جدید را به مطلبی در سایت جاری، توسط Postman شبیه سازی کنیم. برای اینکار، توسط مرورگر کروم به سایت وارد شده و پس از لاگین و تنظیم خودکار کوکی‌های اعتبارسنجی، برگه‌ی developer tools مرورگر را باز کرده و در آن، قسمت network را انتخاب کنید:


در اینجا گزینه‌ی preserve log را نیز انتخاب کنید تا پس از ارسال درخواستی، سابقه‌ی عملیات، پاک نشود. سپس به صورت معمولی به مطلبی امتیاز دهید. اکنون بر روی مدخل درخواست آن کلیک راست کرده و از منوی ظاهر شده، گزینه‌ی Copy->Copy as cURL را انتخاب کنید تا این عملیات و تمام جزئیات مرتبط با آن‌را تبدیل به یک دستور cURL کرده و به حافظه کپی کند.
سپس در postman، از منوی بالای صفحه، سمت چپ آن، گزینه‌ی Import را انتخاب کنید:


در ادامه این دستور کپی شده‌ی در حافظه را در قسمت Paste Raw Text، قرار دهید و بر روی دکمه‌ی import کلیک کنید:


در این حالت postman این دستور را پردازش کرده و فیلدهای ساخت یک درخواست را به صورت خودکار پر می‌کند.

یک نکته‌ی مهم: در حالت انتخاب Copy->Copy as cURL در مرورگر کروم، دو گزینه‌ی cmd و bash موجود هستند. حالت bash را باید انتخاب کنید تا توسط postman به دسترسی parse شود. حالت cmd یک چنین خروجی مشکل داری را در postman تولید می‌کند که قابل ارسال به سمت سرور نیست:


اما جزئیات حالت bash آن، به درستی parse شده‌است و قابلیت send مجدد را دارد:



کار با کوکی‌ها در Postman

کوکی‌ها نیز در اصل به صورت یک هدر HTTP به صورت خودکار توسط مرورگرها به سمت سرور ارسال می‌شوند؛ اما Postman روش ساده‌تری را برای تعریف و کار با آن‌ها ارائه می‌دهد (و ترجیح می‌دهد که بین کوکی‌ها و هدرها تفاوت قائل شود؛ هم در زمان ارسال و هم در زمان نمایش response که در کنار قسمت هدرهای دریافتی از سرور، لیست کوکی‌های دریافتی نیز به صورت مجزایی نمایش داده می‌شوند).


با کلیک بر روی لینک Cookies، در ذیل قسمتی که آدرس یک درخواست تنظیم می‌شود، قسمت مدیریت کوکی‌ها نیز ظاهر خواهد شد که با انتخاب هر نامی در اینجا، می‌توان مقدار آن‌را ویرایش و یا حتی حذف کرد. در این لیست، تمام کوکی‌هایی را که تاکنون تنظیم کرده باشید، می‌توانید مشاهده کنید (و مختص به برگه‌ی خاصی نیست) و همانند قسمت مدیریت کوکی‌های یک مرورگر رفتار می‌کند.
روش کار با آن نیز به این صورت است: ابتدا باید یک دومین را اضافه کنید. سپس ذیل دومین اضافه شده، دکمه‌ی Add cookie ظاهر می‌شود و به هر تعدادی که لازم باشد، می‌توان برای آن دومین کوکی تعریف کرد:


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


به اشتراک گذاری سابقه‌ی درخواست‌ها

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


با کلیک بر روی آن، یکی از گزینه‌های آن، export نام دارد که جزئیات تمام درخواست‌های یک مجموعه را به صورت یک فایل JSON ذخیره می‌کند. برای نمونه فایل JSON خروجی دو قسمت قبل این سری را می‌توانید از اینجا دریافت کنید: httpbin.postman_collection.json
پس از تولید این فایل JSON، برای بازیابی آن می‌توان از دکمه‌ی Import که در منوی سمت چپ، بالای postman قرار دارد، استفاده کرد که نمونه‌ای از آن‌را برای Import جزئیات درخواست‌های cURL پیشتر مشاهده کردید. در اینجا، همان اولین گزینه‌ی دیالوگ Import که Import file نام دارد، دقیقا برای همین منظور تدارک دیده شده‌است.
نظرات مطالب
توسعه سیستم مدیریت محتوای DNTCms - قسمت اول
"(مثلا به محض ثبت شدن منوهایش به صفحه اصلی افزوده شود) نیاز به جدوالی برای ثبت و مدیریت آنها می‌باشد"
اگر قرار باشد سیستم به صورت ماژولار توسعه داده شود ، لزومی ندارد جدول جدایی برای این مورد در نظر گرفت. راه حل‌های سریعتری هم هست ازجمله ذخیره اطلاعات آنها در فایل‌های XML یا حتی خیلی ساده‌تر از آن ، ذخیره نام سیستمی ماژول‌های فعال شده توسط مدیریت در قالب یک رکورد در جدول Setting سیستم که دارای دو فیلد Key و Value میباشد.
نظرات مطالب
React 16x - قسمت 27 - احراز هویت و اعتبارسنجی کاربران - بخش 2 - استخراج و نمایش اطلاعات JWT و خروج از سیستم
در مطلب فوق عنوان شد « برای logout کاربر تنها کافی است توکن او را از local storage حذف کنیم. »
مطابق مطلب  اعتبارسنجی مبتنی بر JWT در ASP.NET Core 2.0 بدون استفاده از سیستم Identity    نیازی به حذف توکن از سمت سرور و دیتابیس نیست؟
مطالب
آپلود فایل توسط فرم‌های پویای jqGrid
پیشنیازها
Ajax.BeginForm و ارسال فایل به سرور در ASP.NET MVC
فعال سازی و پردازش صفحات پویای افزودن، ویرایش و حذف رکوردهای jqGrid در ASP.NET MVC
فرمت کردن اطلاعات نمایش داده شده به کمک jqGrid در ASP.NET MVC
استفاده ازExpressionها جهت ایجاد Strongly typed view در ASP.NET MVC


فرم‌های پویای jqGrid نیز به صورت Ajax ایی به سرور ارسال می‌شوند و اگر نوع عناصر تشکیل دهنده‌ی آن‌ها file تعیین شوند، قادر به ارسال این فایل‌ها به سرور نخواهند بود. در ادامه نحوه‌ی یکپارچه سازی افزونه‌ی AjaxFileUpload را با فرم‌های jqGrid بررسی خواهیم کرد.


تغییرات فایل Layout برنامه

در اینجا دو فایل جدید ajaxfileupload.js و jquery.blockUI.js به مجموعه‌ی فایل‌های تعریف شده اضافه شده‌اند:
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title - My ASP.NET Application</title>

    <link href="~/Content/themes/base/jquery.ui.all.css" rel="stylesheet" />
    <link href="~/Content/jquery.jqGrid/ui.jqgrid.css" rel="stylesheet" />
    <link href="~/Content/Site.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <div>
        @RenderBody()
    </div>

    <script src="~/Scripts/jquery-1.7.2.min.js"></script>
    <script src="~/Scripts/jquery-ui-1.8.11.min.js"></script>
    <script src="~/Scripts/i18n/grid.locale-fa.js"></script>
    <script src="~/Scripts/jquery.jqGrid.src.js"></script>
    <script src="~/Scripts/ajaxfileupload.js"></script>
    <script src="~/Scripts/jquery.blockUI.js"></script>

    @RenderSection("Scripts", required: false)
</body>
</html>
از فایل jquery.blockUI.js برای نمایش صفحه‌ی منتظر بمانید تا فایل آپلود شود، استفاده خواهیم کرد.
 PM> Install-Package jQuery.BlockUI



نکته‌ای در مورد واکنشگرا کردن jqGrid

اگر می‌خواهید عرض jqGrid به تغییرات اندازه‌ی مرورگر پاسخ دهد، تنها کافی است تغییرات ذیل را اعمال کنید:
<div dir="rtl" id="grid1" style="width:100%;" align="center">
    <div id="rsperror"></div>
    <table id="list" cellpadding="0" cellspacing="0"></table>
    <div id="pager" style="text-align:center;"></div>
</div>


    <script type="text/javascript">
        $(document).ready(function () {

            // Responsive jqGrid
            $(window).bind('resize', function () {
                var targetContainer = "#grid1";
                var targetGrid = "#list";

                $(targetGrid).setGridWidth($(targetContainer).width() - 2, true);
            }).trigger('resize');


            $('#list').jqGrid({
                caption: "آزمایش هفتم",
                /// .....
            }).navGrid(
                /// .....
            ).jqGrid('gridResize', { minWidth: 400, minHeight: 150 });
        });
    </script>
در اینجا به تغییرات resize صفحه گوش فرا داده شده و سپس به کمک متد توکار setGridWidth، به صورت پویا اندازه‌ی عرض jqGrid تغییر خواهد کرد.
همچنین اگر می‌خواهید کاربر بتواند اندازه‌ی گرید را دستی تغییر دهد، به انتهای تعاریف گرید، تعریف متد gridResize را نیز اضافه کنید.




نحوه‌ی تعریف ستونی که قرار است فایل آپلود کند

                colModel: [
                    {
                        name: '@(StronglyTyped.PropertyName<Product>(x=>x.ImageName))',
                        index: '@(StronglyTyped.PropertyName<Product>(x => x.ImageName))',
                        align: 'center', width: 220,
                        editable: true,
                        edittype: 'file',
                        formatter: function (cellvalue, options, rowObject) {
                            return "<img src='/images/" + cellvalue + "?rnd=" + new Date().getTime() + "' />";
                        },
                        unformat: function (cellvalue, options, cell) {
                            return $('img', cell).attr('src').replace('/images/', '');
                        }
                    }
                ],
edittype ستونی که قرار است فایل آپلود کند، باید به file تنظیم شود. همچنین چون در اینجا این فایل آپلودی، تصویر یک محصول است، از formatter برای تبدیل مسیر فایل به تصویر و از unformat برای بازگشت این مسیر به مقدر اصلی آن استفاده خواهیم کرد. از unformat برای حالت ویرایش اطلاعات استفاده می‌شود. از formatter برای تغییر اطلاعات دریافتی از سرور به فرمت دلخواهی در سمت کلاینت می‌توان کمک گرفت.
Rnd اضافه شده به انتهای آدرس تصویر، جهت جلوگیری از کش شدن آن تعریف شده‌است.



کتابخانه‌ی JqGridHelper

در قسمت‌های قبل مطالب بررسی jqGrid یک سری کلاس مانند JqGridData برای بازگشت اطلاعات مخصوص jqGrid و یا JqGridRequest برای دریافت پارامترهای ارسالی توسط آن به سرور، تهیه کردیم؛ به همراه کلاس‌هایی مانند جستجو و مرتب سازی پویای اطلاعات.
اگر این کلاس‌ها را از پروژه‌ها و مثال‌های ارائه شده خارج کنیم، می‌توان به کتابخانه‌ی JqGridHelper رسید که فایل‌های آن در پروژه‌ی پیوست موجود هستند.
همچنین در این پروژه، کلاسی به نام StronglyTyped با متد PropertyName جهت دریافت نام رشته‌ای یک خاصیت تعریف شده‌است. گاهی از اوقات این تنها چیزی است که کدهای سمت کلاینت، جهت سازگار شدن با Refactoring و Strongly typed تعریف شدن نیاز دارند و نه ... محصور کننده‌هایی طویل و عریض که هیچگاه نمی‌توانند تمام قابلیت‌های یک کتابخانه‌ی غنی جاوا اسکریپتی را به همراه داشته باشند.
با کمی جستجو، برای jqGrid نیز می‌توانید از این دست محصور کننده‌هارا پیدا کنید اما ... هیچکدام کامل نیستند و دست آخر مجبور خواهید شد در بسیاری از موارد مستقیما JavaScript نویسی کنید.



یکپارچه سازی افزونه‌ی AjaxFileUpload با فرم‌های jqGrid

پس از این مقدمات، ستون ویژه‌ی actions که inline edit را فعال می‌کند، چنین تعریفی را پیدا خواهد کرد:
                colModel: [
                    {
                        name: 'myac', width: 80, fixed: true, sortable: false,
                        resize: false, formatter: 'actions',
                        formatoptions: {
                            keys: true,
                            afterSave: function (rowid, response) {
                                doInlineUpload(response, rowid);
                            },
                            delbutton: true,
                            delOptions: {
                                url: "@Url.Action("DeleteProduct","Home")"
                            }
                        }
                    }
                ],
در اینجا afterSave اضافه شده‌است تا کار ارسال فایل به سرور را در حالت ویرایش inline فعال کند.
و ویژگی‌های قسمت‌های edit، add و delete فرم‌های پویای jqGrid باید به نحو ذیل تغییر کنند:
            $('#list').jqGrid({
                caption: "آزمایش هفتم",
                // ....
            }).navGrid(
                '#pager',
                //enabling buttons
                { add: true, del: true, edit: true, search: false },
                //edit option
                {
                    width: 'auto',
                    reloadAfterSubmit: true, checkOnUpdate: true, checkOnSubmit: true,
                    beforeShowForm: function (form) {
                        centerDialog(form, $('#list'));
                    },
                    afterSubmit: doFormUpload,
                    closeAfterEdit: true
                },
                //add options
                {
                    width: 'auto', url: '@Url.Action("AddProduct","Home")',
                    reloadAfterSubmit: true, checkOnUpdate: true, checkOnSubmit: true,
                    beforeShowForm: function (form) {
                        centerDialog(form, $('#list'));
                    },
                    afterSubmit: doFormUpload,
                    closeAfterAdd: true
                },
                //delete options
                {
                    url: '@Url.Action("DeleteProduct","Home")',
                    reloadAfterSubmit: true
                }).jqGrid('gridResize', { minWidth: 400, minHeight: 150 });
با اکثر این تنظیمات در مطلب «فعال سازی و پردازش صفحات پویای افزودن، ویرایش و حذف رکوردهای jqGrid در ASP.NET MVC» آشنا شده‌اید. تنها قسمت جدید آن شامل رویدادگردان afterSubmit است. در اینجا است که افزونه‌ی AjaxFileUpload فعال شده و سپس اطلاعات المان فایل را به سرور ارسال می‌کند.
افزونه‌ی AjaxFileUpload پس از ارسال اطلاعات عناصر غیر فایلی فرم، باید فعال شود. به همین جهت است که از رویداد afterSubmit در حالت نمایش فرم‌های پویا و رویداد afterSave در حالت ویرایش inline استفاده کرده‌ایم.
در ادامه تعاریف متدهای doInlineUpload و doUpload بکار گرفته شده در رویداد afterSubmit را مشاهده می‌کنید:
        function doInlineUpload(response, rowId) {
            return doUpload(response, null, rowId);
        }

        function doFormUpload(response, postdata) {
            return doUpload(response, postdata, null);
        }

        function doUpload(response, postdata, rowId) {
            // دریافت خروجی متد ثبت اطلاعات از سرور
            // و استفاده از آی دی رکورد ثبت شده برای انتساب فایل آپلودی به آن رکورد
            var result = $.parseJSON(response.responseText);
            if (result.success === false)
                return [false, "عملیات ثبت موفقیت آمیز نبود", result.id];

            var fileElementId = '@(StronglyTyped.PropertyName<Product>(x=>x.ImageName))';
            if (rowId) {
                fileElementId = rowId + "_" + fileElementId;
            }

            var val = $("#" + fileElementId).val();
            if (val == '' || val === undefined) {
                // فایلی انتخاب نشده
                return [false, "لطفا فایلی را انتخاب کنید", result.id];
            }

            $('#grid1').block({ message: '<h4>در حال ارسال فایل به سرور</h4>' });
            $.ajaxFileUpload({
                url: "@Url.Action("UploadFiles", "Home")", // مسیری که باید فایل به آن ارسال شود
                secureuri: false,
                fileElementId: fileElementId, // آی دی المان ورودی فایل
                dataType: 'json',
                data: { id: result.id }, // اطلاعات اضافی در صورت نیاز
                complete: function () {
                    $('#grid1').unblock();
                },
                success: function (data, status) {
                    $("#list").trigger("reloadGrid");
                },
                error: function (data, status, e) {
                    alert(e);
                }
            });

            return [true, "با تشکر!", result.id];
        }
امضای رویدادگردان‌های afterSubmit و afterSave یکی نیست. به همین جهت دو متد اضافی به جای یک متد doUpload مورد استفاده قرار گرفته‌اند.
متد doUpload توسط پارامتر response، اطلاعات بازگشتی پس از ذخیره سازی متداول اطلاعات فرم را دریافت می‌کند. برای مثال ابتدا اطلاعات معمولی یک محصول در بانک اطلاعاتی ذخیره شده و سپس id آن به همراه یک خاصیت به نام success از طرف سرور بازگشت داده می‌شوند.
اگر success مساوی true بود، ادامه‌ی کار آپلود فایل انجام خواهد شد. در اینجا ابتدا بررسی می‌شود که آیا فایلی از طرف کاربر انتخاب شده‌است یا خیر؟ اگر خیر، یک پیام اعتبارسنجی سفارشی به او نمایش داده خواهد شد.
خروجی متد doUpload حتما باید به شکل یک آرایه سه عضوی باشد. عضو اول آن true و false است؛ به معنای موفقیت یا عدم موفقیت عملیات. عضو دوم پیام اعتبارسنجی سفارشی است و عضو سوم، Id ردیف.
در ادامه افزونه‌ی jQuery.BlockUI فعال می‌شود تا ارسال فایل به سرور را به کاربر گوشزد کند.
سپس فراخوانی متداول افزونه‌ی ajaxFileUpload را مشاهده می‌کنید. تنها نکته‌ی مهم آن فراخوانی متد reloadGrid در حالت success است. به این ترتیب گرید را وادار می‌کنیم تا اطلاعات ذخیره شده در سمت سرور را دریافت کرده و سپس تصویر را به نحو صحیحی نمایش دهد.



کدهای سمت سرور آپلود فایل

        [HttpPost]
        public ActionResult AddProduct(Product postData)
        {
            // ...
            return Json(new { id = postData.Id, success = true }, JsonRequestBehavior.AllowGet);
        }

        [HttpPost]
        public ActionResult EditProduct(Product postData)
        {
            // ...
            return Json(new { id = postData.Id, success = true }, JsonRequestBehavior.AllowGet);
        }


        // todo: change `imageName` according to the form's file element name
        [HttpPost]
        public ActionResult UploadFiles(HttpPostedFileBase imageName, int id)
        {
            // ....
            return Json(new { FileName = product.ImageName }, "text/html", JsonRequestBehavior.AllowGet);
        }
در اینجا تنها نکته‌ی مهم، خروجی‌های JSON این متدها هستند.
در حالت‌های Add و Edit، نیاز است id رکورد ثبت شده بازگشت داده شود. این id در سمت کلاینت توسط پارامتر response دریافت می‌شود. از آن در افزونه‌ی ارسال فایل به سرور استفاده خواهیم کرد. اگر به متد UploadFiles دقت کنید، این id را دریافت می‌کند. بنابراین می‌توان یک ربط منطقی را بین فایل ارسالی و رکورد متناظر با آن برقرار کرد.
Content type مقدار بازگشتی از متد UploadFiles حتما باید text/html باشد (افزونه‌ی ارسال فایل‌ها، اینگونه کار می‌کند).


کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید:
jqGrid07.zip
مطالب
آموزش MDX Query - قسمت پنجم – باز کردن یک پایگاه داده ی Multidimensional در محیط BIMS و ساخت یک پروژه ی جدید.

در این قسمت در ابتدا نحوه‌ی باز کردن یک پایگاه داه‌ی چند بعدی را در محیط BIMS بررسی کرده و سپس چگونگی ساخت یک MDB را از پایه بررسی می‌کنیم. برای ادامه دادن این قسمت نیاز می‌باشد که پایگاه داده‌ی AdventureWorkDW2008 را در SSAS نصب کرده باشید .

در ابتدا مطابق شکل زیر منوی File سپس زیر منوی Open و Analysis Service Database را انتخاب نمایید. 


  در ادامه می‌بایست نام Server را مشخص نمایید و دقت داشته باشید که در اینجا منظور از نام سرور، نام سرور SSAS می‌باشد (در صورتیکه بر روی خود سرور در حال کار می‌باشید از . به جای نام سرور استفاده کنید). سپس در قسمت Database، نام پایگاه داده‌ی چند بعدی را انتخاب نمایید. در صورتی که به جز   Adventure Work DW 2008 ، پایگاه داده‌های چند بعدی دیگری را در SSAS داشته باشید، یک لیست از آنها را مشاهده خواهید کرد و در صورتیکه لیست شما خالی می‌باشد، احتمال دارد نام سرور اشتباه باشد یا روی سرویس SSAS مربوط به آن سرور هیچ پایگاه داده‌ی چند بعدی نصب نباشد.

حال مسیری را برای ذخیره سازی پروژه‌ی جدید در نظر بگیرید:  


 

پس از کمی شکیبایی، واکشی اطلاعات از روی پایگاه داده‌ی چند بعدی انتخاب شده انجام می‌شود و یک پروژه در ارتباط با آن پایگاه داده ساخته می‌شود. 


 

همان طور که مشخص می‌باشد، یک شیء درون شاخه‌ی Data Source وجود دارد که مشخص کننده‌ی ارتباط این پروژه با پایگاه داده‌ی Data Warehouse  است. برای مشاهده‌ی این ارتباط، بر روی Adventure Work DW کلیک راست کنید و سپس گزینه‌ی Open را انتخاب نمایید. در ادامه گزینه‌ی Edit را بزنید. 


 

سپس در پنجره‌ی جدید، تنظیمات رشته‌ی ارتباطی با DW را مشاهده نمایید 


 

با زدن کلید Test Connection باید پیام Test Connection Succeeded را مشاهده نمایید. اکنون پنجره‌ها را با زدن کلید OK ببندید.

در قسمت Data Source View سه شی تعریف شده است؛ براساس دسته بندی مورد نظر و جاری در Business موجود در Adventure Work  .

با کلیک راست کردن بر روی Adventure Works DW  و انتخاب گزینه‌ی Open، اقدام به باز کردن DSV انتخاب شده کنید. در صفحه‌ی باز شده می‌توانید انواع دیاگرام تهیه شده را مشاهده نمایید و همچنین لیستی از جداول موجود در این DSV مشخص می‌باشد. 


 

با کلیک راست کردن در فضای خالی دیاگرام ، امکان Add/Remove کردن جداول را به دیاگرام دارید. 


 

در شکل بالا بعد از انتخاب یک جدول در سمت راست و انتقال آن به سمت چپ می‌توانید با زدن دکمه‌ی Add Related Table براساس کلید‌های خارجی، جداول مرتبط با جدول انتخاب شده را به صورت خودکار انتخاب نمایید و به قسمت چپ انتقال دهید.

شما در ساخت Cube مشخص می‌نمایید که Cube را از کدام DSV خواهید ساخت. بنابراین انتخاب جداول در DSV ‌ها می‌بایست براساس نوع Business شما باشد تا در ساخت Cube به مشکلی برخورد نکنید.

 

در ساختار درختی موجود در پنجره‌ی Solution در شاخه‌ی Cube، می‌توانید Adventure Works را باز کنید (کلیک راست و انتخاب Open ) . 

 

در شکل بالا در سمت چپ، می‌توانید Measure ‌ها و Dimension ‌های موجود در این Cube را مشاهده کنید. همچنین در قسمت بالا چندین Tab وجود دارند که در هر کدام تنظیمات بیشتری را بر روی Cube اعمال می‌کنیم. با توجه به اینکه طراحی Cube ‌ها کاری تخصصی می‌باشد و نیاز به اطلاعات زیادی دارد اجازه دهید مقاله ای در خصوص طراحی Cube در SSAS جداگانه انتشار داده شود و فعلا در همین حد بسنده کنیم. با این حال در صورت نیاز می‌توانید برای اطلاعات بیشتر در این خصوص کتاب Microsoft SQL Server Analysis Services 2008 With MDX از انتشارات Wrox را مطالعه نمایید.

در Solution Explorer در شاخه‌ی ،Dimensions می‌توانید تمامی بعدهایی که در تمامی Cube ‌های شما استفاده شده‌اند را مشاهده نمایید.

با انتخاب یک بعد  (ترجیحا بعد Date ) و با کلیک راست کردن و انتخاب گزینه‌ی Open آن را باز نمایید. 



در پنجره‌ی باز شده می‌توانید 4 Tab در بالا را مشاهد نمایید و در Tab نخست، Attribute  ها و همچنین ساختار Hierarchies و در آخر Data source View را مشاهده نمایید.

در Attribute relationships  می توانید ارتباط صفت‌های یک بعد را مشخص نمایید. 



در Browsing Tab می‌توانید محتوای Dimension را بررسی نمایید (البته اگر در پروژه‌ی جدید قرار دارید حتما می‌بایست پروژه را Deploy کرده باشید. در حالتیکه یک پایگاه داه‌ی چند بعدی را باز می‌کنید، نیازی به Deploy کردن نمی‌باشد؛ زیرا حتما قبلا این کار انجام شده است (زیرا شما پایگاه داده‌ی چند بعدی را بعد از Deploy کردن پروژه‌ی SSAS خواهید داشت )) 


 

در صورتیکه مانند روش بالا یک پایگاه داده‌ی چند بعدی را باز کنیم، دیگر نیازی به Deploy کردن نمی‌باشد و فقط برای اعمال تغییرات روی پایگاه داده‌ی چند بعدی باید پروژه را Process کنیم و برای این منظور روی نام پروژه کلیک راست کرده و گزینه‌ی Process را انتخاب کنید. با این کار تغییرات اعمال شده در BIMS روی پایگاه داده‌ی SSAS اعمال می‌گردند و داده‌ها با توجه به ساختار Cube ‌ها دوباره پردازش می‌شوند. 


 

  برای ساخت یک پروژه‌ی جدید به شکل زیر عمل می‌کنیم :

  در ابتدا BIMS را باز کرده و سپس به منوی File رفته و در قسمت New گزینه‌ی Project را انتخاب می‌کنیم. سپس در صفحه‌ی باز شده، مطابق شکل زیر عمل کرده و یک پروژه از نوع Analysis Service Multidimensional … می‌سازیم.


سپس برروی شاخه‌ی Data Source کلیک راست کرده و گزینه‌ی New Data Source را می‌زنیم و پنجره‌های ویزارد را به جلو می‌رویم. 


 

در ابتدا باید یک Connection به DW تولید کنیم. برای این منظور در پنجره‌ی فوق دکمه‌ی New را زده و اطلاعات را مطابق شکل زیر پر می‌کنیم. 


 

و سپس OK را میزنیم.

در صورتی که SSAS در یک سرور دیگر نصب شده است در پنجره‌ی بعدی نیاز می‌باشد نام کاربری را که به سرویس SSAS در آن سرور دسترسی دارد را وارد کنیم.

در صورتی که SSAS روی سیستم Local نصب شده است و کاربری که با آن Login هستیم دسترسی کافی به SSAS را دارد، گزینه‌ی Use the credentials of the current user را انتخاب می‌کنیم. 


 

در صفحه‌ی آخر یک نام برای DS انتخاب می‌کنیم.

سپس نیاز می‌باشد یک DSV بسازیم. برای این منظور روی شاخه‌ی Data Source View کلیک راست کرده و گزینه‌ی New را انتخاب کرده و سپس در پنجره‌ی Wizard باید Data Source ساخته شده در مرحله‌ی قبل را انتخاب کرده و سپس Next را بزنیم. در اینجا بر اساس بیزینس‌های مختلف، راه کار‌های گوناگونی را داریم. به عبارت دیگر می‌توان جداول Fact و Dimension ‌های مرتبط با آن‌را بر اساس زیر سیستم‌های مختلف انتخاب کرده و برای هر کدام از آنها یک DSV بسازیم. به نظر من می‌توانیم تمامی جداول را در این مرحله انتخاب کرده و سپس این تفکیک بندی را در سطح Cube ‌ها انجام داد. به طور کلی دقت داشته باشید به هیچ عنوان DSV و Cube ‌های سیستم را خیلی تفکیک نکنید. زیرا در نوشتن کوئری‌ها و Join بین Cube ‌ها با مشکل و سختی روبرو خواهید شد. (از لحاظ تجربی تفکیک بندی به شرطی صورت گیرد که نیازی به Join  کردن Cube ‌ها در MDX Query ‌ها نباشد.)


سپس یک نام برای DSV خود انتخاب کرده و Finish را بزنید.

خوب؛ آخرین مرحله ساخت Cube می‌باشد (البته در طراحی Cube مطالب بسیاری وجود دارند که در یک مقاله‌ی دیگر تلاش خواهم کرد تمامی آن موارد را توضیح دهم.)

برای ساخت Cube ، روی شاخه‌ی Cube کلیک راست کرده و گزینه‌ی New را بزنید.

سپس Use Existing Table را انتخاب کرده و Next را بزنید. 



در پنجره‌ی بعدی باید DSV را انتخاب کرد و بعد جداول مورد نیاز در طراحی Cube را انتخاب کنید. فراموش نکنید در صورت انتخاب یک Fact  تمامی Dimension ‌های مرتبط با آن را انتخاب نماید. دکمه Next  را بزنید. 



در پنجره‌ی بعدی باید جداول Fact را انتخاب کرده و دکمه‌ی Next را بزنید. 



سپس در پنجره‌ی بعدی دایمنشن را انتخاب نمایید. (ترجیحا اجازه بدهید خود BIMS برای شما Dimension ‌ها را بسازد، هرچند که خود شما می‌توانید بعدا به صورت دستی Dimension ‌ها را ایجاد کنید).



بعد از زدن دکمه‌ی Next نامی برای Cube خود انتخاب نمایید و سپس دکمه‌ی Finish را بزنید.

  بعد از ساخت Cube ، چندین دایمنشن به صورت خودکار ساخته می‌شوند . البته گاهی نیاز می‌باشد که اقدام به ساخت ساختار‌های سلسله مراتبی در Dimension ‌ها کنیم (این مورد را در یک مقاله جداگانه آموزش خواهم داد.)

  پروژه با کلید‌های ترکیبی Ctrl+Shift+B ساخته می‌شود و بعد از اطمینان از درست بودن ساخت پروژه، آن را باید Deploy کرد.

  برای Deploy کردن یک پروژه کافی است بعد از تنظیم کردن رشته‌ی ارتباطی در DS (قبلا توضیح داده شده است) روی پروژه کلیک راست کرده و گزینه‌ی Deploy را بزنیم.