یادداشتهای یک برنامه نویس

بیان تجربیات و دیدگاه های یک برنامه نویس در مورد نرم افزار , طراحی و تولید برنامه با استفاده از تکنولوژی های مایکروسافت

یادداشتهای یک برنامه نویس

بیان تجربیات و دیدگاه های یک برنامه نویس در مورد نرم افزار , طراحی و تولید برنامه با استفاده از تکنولوژی های مایکروسافت

۳ مطلب با کلمه‌ی کلیدی «getJSON» ثبت شده است


    تا اینجا شاید این سوال مطرح شده باشد که با وجود JQuery (که بوضوح عملیات مشابه در مقایسه با JavaScript از کیفیت ، سرعت و دقت بالاتری برخوردار است) طرح برخی جزییات در مورد JavaScript غیر ضروری و بی اهمیت باشد . اما باید توجه داشت که علیرغم اینکه JQuery مخصوصا در زمینه سازگاری با مرورگرهای مختلف و انجام عملیاتی که انتظار داریم از Syntax و روشهای بسیار ساده تری استفاده می کند ، به همان میزان برنامه نویس از بسیاری از جزییات دور نگاه داشته می شود که به نظر می رسد مخصوصا با شرایطی که امروز وجود دارد، حداقل درک بسیاری از این جزییات برای برنامه نویسانی که از تکنولوژی های ASP .NET MVC و WEB API استفاده می کنند ، ضروری است . حداقل درک عمیقی از مفاهیم Request و Response ، Synchronous و Asynchronous ، وجه تمایز بین Verb های HTTP، ساختار URL و نقش AJAX قطعا برنامه نویس را در اتخاذ روش های مناسب و کارآمد یاری داده و امکان انتخاب رویکرد صحیح را در شرایط متنوع میسر می سازد . 
مخصوصا در AJAX موضوع در Javascript کاملا با دقت و تمرکز بیشتری بررسی شده و پس از آن روشهای بسیار ساده تری که در JQuery برای انجام همین عملیات تدارک دیده شده اند معرفی خواهند شد .

در ساده ترین حالت، همه Message ها یا پیام های HTTP در دو گروه عمده Request و Response قابل تقسیم بندی هستند . واضح است که چنانچه از نام آنها نیز مشخص می باشد Request عبارت است از یک درخواست که اطلاعات دقیق تر این درخواست در قالب یک پکیج اطلاعاتی شامل Request Header و Request Body جهت دریافت محتوای اطلاعاتی خاص (Contents) یا انجام عملیات خاص (Actions) به یک سرویس دهنده ارسال می شود . آدرس یا مشخصه یکتایی (Unique) سرویس دهنده در URL و به طور دقیق تر در Request Header قرار می گیرد . 
همچنین اطلاعات ارسال شده در این پکیج شامل یک مشخصه خاص به نام Method یا Verb می باشد. بر اساس اطلاعات ارائه شده پروتکل HTML 1.1 در RFC 2616 ، از مهمترین انواع Method ها می توان به GET و POST اشاره کرد . بر اساس استاندارد مطرح شده توسط W3C تعداد Method ها در واقع بیش از این دو می باشد که در حال حاضر ذکر آنها ضروری نیست . برای اطلاعات دقیقتر می توانید به مستندات W3C و بخشهای مربوط به تقسیم بندی این متدها در RFC 2616 در زیر:

 

http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

 

مراجعه نمایید.
امروزه همه مرورگرهای مدرن از هر دو متد GET و POST پشتیبانی می کنند و در مورد سایر متدها اختلاف هایی وجود دارد که جزییات آن در مستندات هر مرورگر وجود دارد . 
قبل از توصیف مختصری در مورد این دو متد و تفاوتهای آنها لازم است توجه داشته باشیم که تایپ URL یا آدرس در Address Bar مرورگر یا کلیک بر روی یک لینک، در حقیقت نمونه های بارز و رایجی از آغاز یک در خواست با متد GET می باشند که از این به بعد آن را Get Request می نامیم . در خواست POST معمولا در مرور گر توسط ارسال (Submit) پکیج اطلاعات یک فرم قابل انجام می باشد که از این به بعد آن را POST Request می نامیم . در اینجا فرض بر این است که خواننده این سطور کاملا با مفهوم Form در HTML و استفاده از Attribute های Action و Method آشنا می باشد . به طور دقیق تر Attribute مشخص شده با نام Method در داخل تگ FORM مشخص کننده نوع متد مورد نظر جهت ارسال پکیج اطلاعات Form به URL یا آدرسی است که در Action ذکر شده است .

نکته:

نظر به اهمیت استفاده از همه ظرفیت های پروتکل HTTP در WEB API ، موضوع توجه و تمایز بین Verb های مستند شده در HTTP 1.0 بسیار اهمیت دارد . حتی در ASP .NET MVC نیز در مقایسه با ASP .NET Web Form موضوع توجه به ویژگیها و موارد استفاده از Verb ها بسیار پر رنگ تر از گذشته مورد توجه برنامه نویسان می باشد . اما در WEB API درک دقیق Verb ها و چنانچه اشاره شد استفاده کامل از حداکثر ظرفیتهای HTTP از اولویت بسیار بالایی برخوردار است . به عبارت دیگر معماری REST حساسیت بسیار ویژه ای نسبت به Verb های متنوع پروتکل HTTP مخصوصا Get ، Post ، Put و Delete داشته و حتی یک مراجعه سطحی به مستندات Web API بوضوح نشان می دهد که اساسا سرویسهای RESTFull بر همین مبنا پایه گذاری شده اند . به طور دقیق Verb های HTML تر در WEB API از یک دیدگاه بسیار خاص )نسبت به نوع عملکرد آنها) طبقه بندی شده اند و در این میان، عامل اصلی تعیین کننده نوع Verb، ساختار ظاهری URL می باشد که بر اساس ساختار اطلاعاتی هدف (اینکه یک آیتم یا یک لیست یا مجموعه باشد) مشخص می گردد. با این توضیحات و با در نظر گرفتن چهار Verb ذکر شده ، می توان به سادگی دریافت که هشت عملیات مختلف و متنوع ، توسط کنترلر های Web API قابل انجام است . مجددا تکرار می کنم که این موضوع کاملا وابسته به ساختار URL می باشد . تقسیم بندی خاصی که پیشتر به آن اشاره شد مفهوم ویژه ای به نام Idempotency را مطرح می سازد که اشاره به این واقعیت مهم است که تکرار عملیات (به عنوان مثال عملیات ناشی از صدور فرمان Refresh یا کلید F5) در Verb های Get و Put و Delete منجر به انجام عملیات یکسانی می گردد و تکرار آن به هیچ وجه مضر یا مخرب نیست . در یک مثال ساده با هربار تکرار URL و آدرس فرضی


http://Nowhere.com/Customers /12345


زیر (که بوضوح می تواند به عنوان یک Get Request به منظور دریافت جزییات اطلاعات مربوط به مشتری (Customer) خاصی با ID و شناسه 12345 تلقی شود) ، آنچه هر بار تکرار خواهد شد تکرار ارائه جزییات اطلاعات یک مشتری با مشخصه CustomerID=12345 خواهد بود . از این جهت این Verb (ها) اصطلاحا Idempotent نامیده می شوند . 
در یک مورد مشابه دیگر اگر URL مثال قبلی را این بار از نوع Put Request در نظر بگیریم (که می تواند به صورت ایجاد یک Instance یا نمونه جدید از یک مشتری با مشخصه CustomerID=12345 تلقی شود) مجددا تکرار این عملیات در نهایت منجر به ایجاد یک نمونه از اطلاعات مشتری خواهد شد که مجددا از همین رو Put یک Verb از نوع Idempotent در نظر گرفته می شود .در مورد Delete هم دقیقا همین وضعیت وجود دارد و از ذکر مثال خودداری شده است. در مجموع این اصطلاح به تعبیری اشاره به Safe بودن یا ایمن بودن ذاتی نوع عملیاتی است که توسط Get و Put و Delete انجام می شود . در مقابل POST هیچگاه به عنوان یک Verb از نوع Idempotent در نظر گرفته نمی شود . چنانچه مطلع هستید استفاده از Post به صورت رایجی در مواقعی است که نیاز به ایجاد یک نمونه جدید از یک Object خاص وجود دارد که بر خلاف وضعیت تشریح شده در Put انتظار داریم سیستم خود یک ID معتبر تولید کرده و (بر اساس سایر اطلاعات تکمیلی که Post شده است) اقدام به ایجاد نمونه جدید بنماید . بدیهی است که تکرار این عملیات مخرب و با هر بار اجرا یک نمونه جدید (بر خلاف مثال های قبل) ایجاد خواهد شد . 
 

ذکر این جزییات فقط تاکید بر این نکته بسیار مهم است که به نظر می رسد باید یک تغییر یا تجدید نظر کلی در نگرش به Verb ها و نوع استفاده از آنها برای برنامه نویسانی که قصد استفاده موثر از Asp .NET MVC و WEB API را دارند ، ایجاد شود . 
در مورد جزییات تمایز بین Verb ها در MVC در ادامه مثالهایی ارائه خوهد شد و ملاحظه خواهیم کرد که بر خلاف ASP .NET Web Form که اجبار به استفاده از یک Form و تشریک مساعی مکانیسم Page Rendering/Server Controls از سوی سیستم تحمیل میشد، در MVC امکان استفاده از چندین Form با Verb های متنوع و حتی استفاده از Asynchronous Request بواسطه استفاده از تکنولوژی AJAX ، شاهد افزایش چشمیگری در کیفیت خواهیم بود.
 

ملاحظاتی در باره Get و Post

در ساده ترین شکل می توان چنین گفت که استفاده از Get Request در مجموع باید صرفا به منظور دریافت (get) اطلاعات (در فرمت های متنوع HTML ، XML ، JSON و ...) از web Server تدارک دیده شود . در مقابل یک Post Request به طور معمول انحصارا برای تغییر (Modify) در اطلاعات (اشاره به Insert و Update و Delete) مورد استفاده قرار می گیرد .
تنها و تنها برنامه نویس مسئول انتخاب استراتژی و انتخاب Verb مناسب ، بعد از تشخیص کامل Idempotent بودن یا Safe بودن یا غیر مخرب بودن عملیات است . عملیاتی نظیر جسجتو در Database یا دریافت گزارش از واضح ترین مصادیق استفاده صحیح از Get Request می باشند . در هنگام انتخاب Get Request موارد زیر باید همیشه مورد توجه باشند :

1- امکان Cache شدن نوع درخواست Get (بر خلاف Post) وجود دارد.
2- در شرایط طبیعی، همواره سابقه درخواست های Get در Browser History ثبت می شوند .
3- امکان نشانه گذاری و Bookmark درخواست های Get وجود دارد .
4- در صورت تمایل به سادگی امکان به اشتراک گذاری (Sharing) در خواست های نوع Get وجود دارند .
5 درخواستهای نوع Get به سادگی قابل دستکاری ، سو استفاده و واضح تر عرض کنم Hack شدن می باشند . بنابراین در هنگام طراحی سیستم پردازش درخواست های Get باید از مکانیسم های مناسب جهت کنترل این ویژگی استفاده کنید که متاسفانه اینجا مجال پرداختن به آنها نیست .
6- مکانیسم درخواست های Get به ترتیبی است که اطلاعات تکمیلی مورد نیاز برای پردازش (در صورت نیاز) در خود URL و توسط مجموعه QueryString به سمت Server هدایت می شود . بدیهیست که معنای دقیقتر آن این است که این مکانیسم به هیچ وجه نباید در ارسال اطلاعات حساسی مثل کلمه عبور ، مشخصات کارتهای اعتباری و ... مورد استفاده قرار بگیرد .

نکته:


بر خلاف یک نظریه غلط که Post Request را روش ایمنی برای موارد مذکور تلقی می کنند ، باید توجه داشت که اصولا موضوع امنیت اساسا هیچ ارتباطی با انتخاب Verb نداشته و باید در نظر گرفت که در Post Request اطلاعات صرفا در بدنه Request قرار می گیرند که تقریبا به همان سهولت روش Get می تواند توسط افراد سوجو مورد سواستفاده قرار بگیرد . 


7- با عنایت به مطلب اشاره شده در آیتم ششم، هر چند هیچ محدودیتی در پروتکل Http جهت تعیین حداکثر اندازه یا تعداد کاراکترهای Query String تعیین نشده اما محدودیت ویژه ای از طرف خود مرورگرها برای این ویژگی وجود دارد . در IE این مقدار حداکثر 2048 (با احتساب سایر مولفه ای موجود در URL) کاراکتر می باشد .
8- در صورت استفاده از Javascript یا ترجیحا JQuery امکان ارسال Asynchronous Get Request با استفاده از تکنولوژی AJAX وجود دارد که مثالهایی از آن در ادامه ارائه خواهد شد . در JQuery متدهای get و getJSON و getScript و load به همین منظور تدارک دیده شده اند .

خلاصه ای از مواردی که در Post Request باید به آن توجه شود به قرار زیر است :

1- در صورتیکه حجم اطلاعاتی نیاز دارید به Server ارسال کنید زیاد باشد بهتر است که روش Post را انتخاب کنید .
2- در صورت نیاز به ارسال اطلاعات حساسی مثل Password و مشخصات کارت های اعتباری و اطلاعات حسابهای بانکی از روش Post (به همراه اطمنیان از سایر مولفه های امنیتی مثل SSL و پروتکل Https ) استفاده نمایید .
3- در شرایط معمولی یک Post Request معمولا با استفاده از ساختار و تگ Form با ذکر Method=Post در HTML میسر می باشد. اما این لزوما به این معنی نیست که تگ Form صرفا برای آغاز یک Post Request کاربرد دارد . بدیهی است که با تغییر در Method امکان تغییر به Get نیز وجود خواهد داشت . چنانچه در ادامه شاهد خواهیم بود با استفاده از AJAX تقریبا امکان استفاده از همه انواع Verb ها وجود دارد .
4- در JQuery متد post برای ایجاد یک Asynchronous Post Request با استفاده از AJAX تدارک دیده شده است .

۲ نظر موافقین ۰ مخالفین ۰ ۰۸ فروردين ۹۴ ، ۱۷:۱۴
مهران حسین نیا

پروژه نمونه بررسی قابلیتهای Google MAP API و تلفیق آن با MVC

     در این پروژه مشخصا امکان استفاده از Google Map API در MVC بهانه ای برای کسب تجربه بیشتر و استفاده از تکنیک های این تکنولوژی در سناریو های مرتبط با GIS می باشد .
در مرحله اول به هیچ وجه از Spatial Data و مخصوصا امکانات استثنایی SQL در محاسبات GIS استفاده نشده و هر آنچه در این پروژه ساده استفاده شده فقط به کار گیری بخشی از تواناییهای مفاهیمی مثل Layout ، View و Partial View و تلفیق JQuery UI و بهره گیری از Google Javascript API V 3.0 و AJAX و JSON می باشد .
به دلیل حفظ ساختار اصلی Template پروژه استاندارد، ابتدا یک Layout مستقل به نام _AppLayout.cshtml ایجاد شده که در فولدر View/Shared قرار گرفته است .
این Layout دارای یک ساختار ساده 2 ستونی Right To Left می باشد که پنل سمت راست در واقع یک Div استاندارد با float متمایل به راست می باشد که اندازه طول (Width) آن 156 پیکسل در نظر گرفته شده است .
پنل سمت راست به طور مشابه دارای یک float متمایل به چپ بوده که به دلیل حفظ فاصله مناسب از سمت راست (Padding-right) دارای طولی (Width) به اندازه 170 پیکسل می باشد .
پنل های Header و Footer هم به سادگی در Layout قرار دارند .
پنل سمت راست در Layout به صورت یک Section ایجاد شده است که وظیفه Rendering و محتویات آن به صورت اختیاری :
 

<div id="rightPanel" >
     @RenderSection("RightPanel", required: false)
</div>

در View میهمان (منظور آن View که از Layout استفاده میکند) تامین میشود که این وظیفه را index.cshtml انجام داده است . برای تامین محتویات پنل سمت راست index.cshtml از یک Partial View ساده به نام _PartialRightMapMenu استفاده کرده است که هدف از این کار (Reusable Controls) استفاده مستقل از این Partial View در بخشهای مختلف برنامه بوده است .
این Partial View شامل یک کنترل استاندارد Accordion در JQuery می باشد که از آن به عنوان منوی اصلی برنامه استفاده شده است . گزینه های هر Category از منو به سادگی با یک Button معمولی ایجاد شده اند .
به دلیل بهره گیری از امکانات آخرین نسخه JQuery من تصمیم گرفتم که از نسخه 1.10.2 که در زمان تهیه این برنامه آخرین نسخه آن بوده است استفاده کنم . رفرنس به اسکریپت های مورد نیاز از طریق تکنیک Bundle در MVC انجام شده است که جزییات آن در فایل BundleConfig قابل مشاهده است .
همچنین برای استفاده از Google API درج یک رفرنس به کتابخانه اسکریپت توابع گوگل الزامیست که این کار در داخل index.cshtml انجام شده که این View، نقش میزبان اصلی سناریو های مرتبط با نقشه را بازی میکند .
علاوه بر رفرنس به کتابخانه اصلی اسکریپت های Javascript در Google به دلیل استفاده از سرویس ها و نقشه های وضعیت آب و هوا رفرنس دومی هم به اسکریپت مورد نیاز در همان محل قرار داده شده است .
همچنین کلیه توابع مورد نیاز ما در JQuery و Javascript به طور مستقل در فایل mvcgoogle.js و در فولدر Scripts قرار داده شده است . تقریبا همه عملیات برنامه از داخل این فایل کنترل شده و Event های مربوط به انتخاب گزینه های سمت راست از طریق این فایل Handle می شوند . برای استفاده از این فایل مجددا در BundleConfig.cs آن را به همراه سایر اسکریپت های مورد نیاز برنامه Bundle و بسته بندی کرده ام و در index.cshtml یک رفرنس برای آن در نظر گرفته ام.
در داخل این فایل از استراتژی استفاده از یک متغیر map سراسری و Global استفاده شده است . با توجه به پیش بینی حداقل 30 گزینه در منوی سمت راست و پرهیز از پاسکاری خسته کننده آبجکت map بین توابع فعلا این راهکار مورد استفاده قرار گرفته شده است . مگر آنکه در آینده و در گسترش های بعدی تغییراتی در آن ایجاد گردد .
در اولین نسخه و اولین ارائه این برنامه تعداد 13 سناریوی مختلف بررسی و پیاده سازی شده است که متناسب با هریک از آنها، یک گزینه در منوی سمت راست تدارک دیده شده است . از همان ابتدای فکر طراحی و اجرای این برنامه در نظر داشتم که تنوع زیادی در تکنیک های مرتبط با نقشه استفاده کنم .
مثالها از نمایش یک نقشه ساده شروع شده و انتخاب یک نقطه خاص (در این مثال برج میلاد) و در ادامه امکان ترسیم دلخواه (Custom Style Rendering) در نقشه ها نشان داده شده است . همچنین در گزینه weather استفاده از سرویس وضعیت آب و هوایی و رندر کردن آن روی نقشه توسط Google API نشان داده شده است . همچنین در گزینه "ماهواره – کلیک" نقشه گوگل به صورت Hybrid ترسیم شده است و با هر کلیک بر روی نقشه مختصات محل کلیک شده در نوار Footer انتهای برنامه منعکس خواهد شد . در مجموع جزییات دیگری هم در هر یک از مثالها وجود دارد که توصیه میکنم در هنگام اجرا با دقت به نوع عملیاتی که انجام میشود توجه نمایید .
در این برنامه نمونه و البته ساده، به نظر من یک چارچوب مناسب برای گسترش های آینده ایجاد شده و زمینه برای انجام سناریو های بسیار پیچیده تر نظیر استفاده از داده های جغرافیایی (Sql Spatial Data) در SQL و بهره گیری از معماری SOA با استفاده از WCF مهیا شده است . در Category نام گذاری شده با فرمت KML اختصاصا امکان استفاده از فرمت بسیار مهم KML در Google بررسی شده است . در این باره مطالب زیادی وجود دارد که من توضیح مفصل تر در این مورد را به آینده موکول میکنم و فقط لازم است اشاره کنم که هر 4 گزینه این قسمت اطلاعات خود را از سایت http://earthquake.usgs.gov/ دریافت میکنند که اطلاعات بسیار به روز و طبقه بندی شده را در ارتباط با آمار آخرین زلزله ها حداقل در دو فرمت JSON و KML ارائه میدهد . امکان استفاده از فرمت KML در Google یکی از مزایای استثنایی این API محسوب شده و امکانات موجود در این زمینه بسیار متنوع و جالب می باشند .
تنها محدودیت در این زمینه این است که فایلهای KML باید در یک Domain مستقل و Online قرار داشته باشند و امکان استفاده از فایلها به صورت local وجود ندارد .
تکته بسیار مهمی که باید برای استفاده از این پروژه در نظر داشته باشیداین است که حتما مشخصات ConnectionString را در web.config مطابق با وضعیت سیستم خود تغییر داده و اقدام به استفاده از برنامه نمایید .
در Category سوم استفاده از اطلاعات Dynamic مورد توجه قرار گرفته شده است . برای این کار من یک Database نمونه به نام DBGisSample و به صورت Backup ضمیمه برنامه کرده ام که با SQL Server Express 2012 ایجاد شده و در حال حاضر شامل دو جدول مستقل است . یکی از جدول ها دارای چند رکورد مرتبط با مختصات شهرهای مهم ایران است . دومین جدول مجددا مربوط به اطلاعات زلزله ها ی شدید به تفکیک سال و شدت و زمان آنها می بالشد که فقط توجه به یک نکته بسیار مهم در اینجا ضروریست .
در این جداول به هیچ وجه از امکانات Spatial Data و به طور مشخص نوع داده های Geometry و Geography در Sql استفاده نشده است . هر چند جدول earthquake دارای چنین اطلاعاتی می باشد اما اگر با دقت به هر دو Table نگاه کنیم ، هر کدام از ایk جداول دارای دو ستون مستقل به ترتیب برای طول و عرض جغرافیایی هستند که برنامه ما ابتدا با استفاده از EF اطلاعات این جداول را دریافت کرده و سپس Controller مورد نظر ما به نام Home در MVC آبجکت های موجود در Model را با توجه به اطلاعات دریافت شده از SQL ایجاد کرده و یک لیست Generic از این اطلاعات در فرمت JSON توسط Action ها Serialize شده و دو فراخوانی مستقل و جداگانه از متد $.getJSON در داخل mcvgoogle.js بدون نیاز به Postback و توسط Ajax اطلاعات مورد نیاز ما را به View مورد نظر ما یعنی index منتقل میکند .
بعد از این کار، فراخوانی متدهای مرتبط و مورد نیاز در Google API عملیات ترسیم و Rendering نقاط را انجام داده و هر نقطه دارای یک Tooltip اختصاصی است که سایر اطلاعات و فیلدهای هر رکورد را به این ترتیب نمایش میدهد . بعد ها از infoWindow در Google API برای همین کار استفاده خواهیم کرد که بسیار روش مناسب تری می باشد .
همچنین باید اشاره کنم که در گزینه دوم مربوط به این قسمت، هر چند کار انجام شده بسیار شبیه به گزینه اول می باشد اما تفاوت اندکی وجود دارد :

اولین نکته این است که در گزینه دوم متد Action مورد نظر یعنی SQLEarthQuake دو پارامتر دریافت میکند که من از آن برای محدود کردن تعداد رکورد های دریافتی استفاده کرده ام . در جدول Earthquakes در حدود 5351 رکورد مختلف وجود دارد که متد Action ما با ایجاد یک فیلتر ساده فقط رکورد های مربوط به سال 1960 تا 2013 را دریافت میکند که تعداد رکورد ها تقریبا به نصف کاهش می یابد . پس این Action اولا امکان انتقال پارامتر به متد Action را نشان داده ثانیا بوضوح نشان میدهد که این روش از چه کارآیی و قدرت بالایی برخوردار است که حدود 2500 رکورد را در زمان بسیار کوتاهی بدون Postback دریافت کرده و Google Api به محض دریافت آنها، به ازای هر نقطه یک Pushpin روی نقشه ترسیم میکند .

جزییات انجام این عملیات همه در mvcgoogle.js قابل مطالعه است .
به نظرم می رسد که جزییات زیادی برای مطرح شدن وجود دارد که فعلا به دلیل کوتاه شدن این مطلب از آنها پرهیز میکنم .

لینک دریافت سورس کد پروژه به همراه SQL Data Backup :
https://onedrive.live.com/redir?resid=FC40347DCF4AAF1D%211252

امیدوارم از نظرات و پیشنهادات خود مرا مطلع نمایید .

۱ نظر موافقین ۰ مخالفین ۰ ۰۹ خرداد ۹۳ ، ۲۲:۴۳
مهران حسین نیا
پنجشنبه, ۱ خرداد ۱۳۹۳، ۰۳:۴۱ ب.ظ

گزارش یک تجربـه در MVC

ماجرا از آنجایی آغاز شد که در نظر داشتم سناریویی که در برنامه RouthingDemo قبلا در Windows 8 Store App انجام شده بود را در MVC بازسازی کرده و علاوه بر فرمت GPX ، امکان استفاده از API مشخصی که آن را به منظور کار با Shape File ها و Platform Independent طراحی کرده بودم استفاده کنم. کد کامل این API را در اولین فرصت به همراه توضیحات لازم ارائه خواهم کرد .
 در مجموع هدف من Rendering اطلاعات فرمت های اصلی File-based در GIS یعنی KML ، Shape و Gpx حداقل بر روی سه Base Map متفاوت یعنی استفاده از Provider های Bing Map و Google Map و OpenStreet Map می باشد .
تقریبا هر سه Provider مجهز به API های اختصاصی خود هستند که به طور مشترک در Client-side قابل استفاده بوده و امکان Render نمودن یک Base Map و در ادامه امکان ترسیم Geometry های اصلی در GIS یعنی Point ، Line و Polygon را فراهم نموده و عملیات رایجی مثل Panning و Zooming را میسر میسازند .
در سناریوی نهایی به نظرم رسید که خلاص شدن از شر فرمت های File-based تنها در صورت وجود یک Converter و انتقال اطلاعات موجود در آنها به SQL  در قالب Spatial Data بهترین راهکار موجود است که قبل از پرداختن به جزییات موجود در این راه  اولین نکته روش برقراری ارتباط بین MVC (در دیدگاه کلی Server-side)  و JQuery (اشاره به امکان استفاده از API هر یک از Provider های نقشه )  می باشد که در اینجا گزارشی از تجربه موفقیت آمیزی که با استفاده از AJAX و فرمت JSON  داشته ام ، ارائه شده است .

کلاسی که در زیر ایجاد شده تقریبا منطبق بر اطلاعات موجود در فرمت GPX می باشد .
 

    public class GISRoute

    {

        public GISRoute()

        {

        }

        public double Longitude

        {

            get;

            set;

        }

        public double Latitude

        {

            get;

            set;

        }

        public int Altitude

        {

            get;

            set;

        }

        public DateTime TimePoint

        {

            get;

            set;

        }

 

    }
 

در ادامه کلاس دسترسی به فرمت فایلهای GPX و Encapsulation اطلاعات آن در کلاس GISRoute ایجاد کردم که چندان بهینه نیست اما در ساده ترین شکل خود با ایجاد یک لیست جنریک از کلاس GISRoute اطلاعات موجود در فرمت GPX را در کد زیر، با استفاده از LINQ To XML در لیست Gerneric قرار داده و لیست مذکور جهت استفاده در Controller آماده میشود :

    public class GPXReader

    {

        List<GISRoute> gisrouteList;

        public GPXReader()

        {

            Test tst = new Test();

            gisrouteList = new List<GISRoute>();

            LoadGPXFile();

        }

        public GPXReader(string path)

        {

        }

        public List<GISRoute> GisRouteList

        {

            get

            {

                return this.gisrouteList;

            }

        }

        public void LoadGPXFile()

        {

 

            XDocument xmlFile = XDocument.Load(".....\\Projects\\MvcMap\\MvcMap\\App_Data\\sample.gpx");

            XNamespace xns = "http://www.topografix.com/GPX/1/0/";

            foreach (var element in xmlFile.Root.Elements("trkpt"))

            {

                double lat = double.Parse(element.FirstAttribute.Value);

                double lon = double.Parse(element.LastAttribute.Value);

                int alt = Int32.Parse(element.Element("ele").Value);

                DateTime time = DateTime.Parse(element.Element("time").Value);

                string str = element.Value;

                gisrouteList.Add(new GISRoute

                {

                    Altitude = alt,

                    Latitude = lat,

                    Longitude = lon,

                    TimePoint = time

                });

            }       

        }

    }

 

اینک Controller صرفا با Instantiate کردن کلاس GPXReader می تواند به محض دریافت یک Request از نوع Get ،اطلاعات موجود در یک مسیر ثبت شده در فرمت GPX را در فرمت JSON به صورت اتوماتیک Serialize کرده و آن را به یک View دلخواه (حتی نوع Strongly Typed View)   هدایت نماید .
برای ساده تر شدن موضوع، من از همان View استاندارد Index.cshtml استفاده کردم. کد Action مورد نظر من با نام MyMethod به صورت زیر در کنترلر Home ایجاد شد .

 

  public class HomeController : Controller

    {

        public ActionResult Index()

        {

            ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";

 

            return View();

        }

 

        public ActionResult About()

        {

            ViewBag.Message = "Your app description page.";

            GPXReader gpxReader = new GPXReader();

            return View(gpxReader.GisRouteList);

        }

 

        public ActionResult Contact()

        {

            ViewBag.Message = "Your contact page.";

 

            return View();

        }

        [HttpGet]

        public ActionResult MyMethod(int keyid, int newval)

        {           

GPXReader gpxReader = new GPXReader();

            ViewBag.Message = keyid.ToString() + " " + newval.ToString();

            return Json(new { smylist = gpxReader.GisRouteList },

                        JsonRequestBehavior.AllowGet);

        }

    }

 

چنانچه در کد بوضوح مشاهده میشود با استفاده از Annotation و درست در ابتدای متد، نوع درخواستی که متد MyMethod قادر به Handle کردن آن میباشد Get تعیین شده است . همچنین دو پارامتر موجود در این متد صرفا برای بررسی امکان ارسال پارامتر به این متد به کار رفته و در سناریوی فرضی من از این دو پارامتر استفاده نشده است . به عبارت ساده تر با استفاده از JQuery چنانچه در ادامه خواهیم دید امکان ارسال هر تعداد پارامتر مورد نیاز با هر نوع دلخواه به Action تعیین شده در یک Controller میسر خواهد بود که تواناییهای بالقوه این روش استثنایی را آشکار میکند .

برای آزمایش این روش ابتدا در View میزبان از چند المان HTML ساده به صورت زیر استفاده شده است :

 

        <div>

            <button id="btnStart"JSON Send</button>

            <div id="divReturnedData"> </div>

            <ol id="list">

            </ol>

        </div>

 

واضح است که از Button به عنوان یک Trigger برای آغاز این عملیات استفاده شده و برای نمایش خروجی حاصل از احضار متد می توان از divReturnedData و یا list استفاده کرد که جزییات این کار در ادامه شرح داده شده است .

در ادامه و در مرحله اول عملیات Client-side برای رویداد Click در  Button مورد نظر  مطابق زیر یک Event Handler مشخص می کنیم که در آن بوضوح مشخص شده است که به محض لود شدن کلیه عناصر DOM (با توجه به اینکه معمولا Script ما در Header قرار میگیرد و عناصر DOM و تگ های HTML در Body قرار دارند ، این یک روش مناسب و استاندارد  برای اطمینان از لود شدن کل المانهای DOM می باشد) فراخوانی متد GetJSONWithAjax به محض کلیک بر روی Button تعیین شده با btnStart انجام شود . کد متد GetJSONWithAjax در ادامه ارائه شده است .

 

   <script type="text/javascript">

       $(document).ready(function() {

           $("#btnStart").click(GetJSONWithAjax);

       });

    </script>

 

من در ابتدا با استفاده از متد $.ajax درخواستی از نوع Get به Action و Controller ارسال کرده ام که واضح است در آغاز این فراخوانی نوع درخواست get تعیین شده و فرمت اطلاعات دریافتی json تعیین شده است . همچنین ویژگی Caching در اینجا Disable شده و با استفاده از Helper بسیار مفید و کاربردی Url.Action و توسط Razor ابتدا نام Action یعنی MyMethod و سپس نام Controller یعنی Home تعیین شده است .
چنانچه قبلا اشاره شد متد ما در کنترلر دارای دو پارامتر است که با وجود اینکه ما از آن استفاده نکرده ایم اما برای نمایش امکان ارسال پارامتر به همراه Request مقادیر فرضی 1 و 10 را در پارامترها  مقدار دهی کرده و یک Handler از نوع Anonymous   (منظور function بدون نامی است که دارای یک پارامتر بوده و در حقیقت حاوی اطلاعات ارسال شده از Controller می باشد . به عبارت ساده تر ما از این function به به عنوان Callback در هنگام موفقیت آمیز بودن عملیات استفاده کرده ایم) تعیین کرده و در داخل این Callback (توضیح آنکه Callback اشاره به نوع خاصی از Function ها در عملیات Asynchronous می باشد که در مراحل مختلف این عملیات فراخوانی شده و امکان کنترل کامل در کل این فرآیند را میسر میسازند) ابتدا با دریافت تعداد عناصر لیست یا آرایه از صحت دریافت آنها مطمئن می شویم. هر چند در عمل نیازی هم به انجام این کار نیست و فراخوانی این Callback خود دلیل خوبی برای موفقیت آمیز بودن این عملیات است . از divReturnedData هم به عنوان یک Placeholder برای نمایش تعداد عناصر لیست/آرایه استفاده کرده ام . تردید من در استفاده از واژه لیست و یا  آرایه به این دلیل است که مجموعه ای که به عوان Data منتقل شده است در Controller به صورت یک لیست Generic تدارک دیده شده بود و اینجا آن را به صورت یک آرایه در JQuery دریافت کرده ایم .
به محض دریافت آرایه حالا JQuery دارای مجموعه ای از متد ها و توابع بسیار قدرتمند و کارآمدیست که انواع پردازش های دلخواه را بر روی عناصر آرایه فراهم میکند . این ابزارهای بی نظیر حتی بدون نیاز به یک loop سنتی می توانند کلیه نیازهای موجود در زمینه مرور و Traverse کردن عناصر آرایه و پردازش دلخواه بر روی تک تک اعضای آرایه را فراهم کنند . از مهمترین این توابع میتوان به each ، map و grep اشاره کرد که مخصوصا در مورد آخر با تلفیق با Regular Expression  یک ابزار فوق العاده کارآمد محسوب میشود . من با استفاده از متد each در JQuery کار را به ترتیبی که در کد ملاحظه میکنید ادامه داده ام . این متد در پارامتر اول ، خود آرایه را دریافت کرده و در پارامتر دوم امکان مشخص نمودن یک Callback ،  که به ازای هر عنصری از آرایه فراخوانی میشود را میسر می سازد . مجددا من از یک تابع Anonymous استفاده کرده ام و فقط یک Property در آرایه یعنی Longitude (برای توضیح به کد کلاس GISoute مراجعه نمایید) را در یک تگ Ordered List در HTML نمایش داده ام . توضیح اینکه متد append هر بار به تعداد اعضای آرایه یک node از نوع li به تگ OL اضافه میکند .
متد $.ajax چنانچه مشاهده میکنید امکان تعیین یک Callback در شرایطی که انجام عملیات به هر دلیلی با مشکلی مواجه شود را فراهم میکند .

 

 

           function GetJSONWithAjax() {

               $.ajax({

                   type: 'get',

                   dataType: 'json',

                   cache: false,

                   url: '@Url.Action("MyMethod","Home")',

  data: { keyid: 1, newval: 10 },

  success: function (response) {

      var arrayCount = response.mylist.length;

      var memlist = $("#list");

      $("#divReturnedData").html("<b>" + arrayCount + "</b>);

      $.each(response.mylist, function (index, value) {

          memlist.append($("<li>" + value.Longitude + "</li>"));

      });  },

  error: function (jqXHR, textStatus, errorThrown) {

      //alert('Error ' + errorThrown);

  }

        });

           }

 

با توجه به این نکته بسیار مهم که فرمت اطلاعات دریافت شده در اینجا از نوع JSON می باشد ، به نظر میرسد استفاده از متد $.getJSON نیز علاوه بر امکان رسیدن به نتیجه مشابه ، این کار را با تلاش کمتری میسر میسازد . برای استفاده از آن می توان از کد زیر استفاده کرد که توصیه میکنم به مشابهت های آن با روش قبلی و مزیت آن توجه نمایید .

 

    function GetJSON()

           {

        var params = { keyid: 1, newval: 10 };

        $.getJSON('@Url.Action("MyMethod","Home")',

            params,

            function (response) {

                  var arint = response.mylist.length;

                  var memlist = $("#list");

                  $("#divReturnedData").html(arint + " <b>" + response.mydata + "</b> " + response.oldval + " " + "<hr/> " + response.mylist[0].Longitude);

                  $.each(response.mylist,function( index, value ){

                                  memlist.append($( "<li>" + value.Longitude + "</li>" ));

                  });

        });

 

با توجه به توضیحاتی که قبلا داده شد به نظر میرسد هیچ نقطه مبهمی در این فراخوانی وجود ندارد .
با استفاده از Developer Tools در Google Chrome مطلع شدم که کل این درخواست و دریافت اطلاعات در مدت 550 میلی ثانیه انجام شده اما اگر با دقت به تصویری که ضمیمه شدهاستتوجه کنیم ملاحظه خواهیم کرد که ارسال اطلاعات و زمان مورد نیاز Response فقط 1.5 میلی ثانیه بوده است که برای حدود 1000 رکورد از نوع GISRoute زمان بسیار خوب و نشان دهنده سرعت بالای این روش می باشد . بر طبق گزارش Developer Tools سیستم به مدت 547 میلی ثانیه توقف داشته است که با بهینه سازی کد و روشها میتوان این مقدار را تا یک سوم مقدار فعلی کاهش داد .




 امیدوارم توضیح این تجربه، برای دوستان و همکاران محترم مفید بوده و این عزیزان از  نظرات و پیشنهادهای خود مرا بی نصیب نگذارند .

 

۰ نظر موافقین ۰ مخالفین ۰ ۰۱ خرداد ۹۳ ، ۱۵:۴۱
مهران حسین نیا