دانش و مهارت زیادی لازم نیست تا یک برنامه نوشت. بچههای دبیرستانی نیز این کار را در دبیرستان انجام میدهند. مردان و زنان جوان در دانشگاه با سر هم کردن چند خط کد PHP یا Ruby کسب و کارهای میلیارد دلاری را شروع کرده اند. برنامه نویسان تازه کار زیادی در دفاتر کاری مکعبی شکلشان در سرتاسر دنیا در بین اسناد حجیم نیازمندیهای موجود در سیستمهای issue tracking خود در حال تقلا هستند تا سیستم هایشان را با صرف فعل خواستن توانستن است به کار بیندازند. کدهایی که تولید میکنند ممکن است زیبا نباشند ولی کار میکنند. کار میکند به این دلیل که چیزی بتواند یک بار کار کند، خیلی سخت هم نیست. این که چیزی واقعا به درستی کار کند موضوعی کاملا متفاوت است. پیاده سازی صحیح نرم افزار سخت است چرا که دانش و مهارت هایی نیاز دارد که هنوز بیشتر برنامه نویسان جوان به آن دست نیافته اند.
اشتراکها
سیر تکاملی یک توسعه دهنده به یک طراح
نظرات مطالب
الگوی استراتژی - Strategy Pattern
چرا استراتژی توسط Abstract پیاده سازی شده و از اینترفیس استفاده نشده؟
زمانی که درخواستی به سمت یک Action پارامتر دار ارسال میشود، قسمت ActionInvoker قبل از فراخوانی اکشن مربوطه، به دنبال Model Binder مناسبی برای دادههای پارامترها میگردد و در صورت یافت نشدن، از ModelBinder پیش فرض ASP.NET MVC استفاده میکند.
اما وظیفهی ModelBinder چیست ؟
ModelBinder دادههای ارسال شده از مرورگر را که توسط درخواستهای HTTP (کوئری استرینگها و یا دادههای همراه با فرمها ) ارسال شده است، تبدیل به دادههای قابل فهم برای پارامترها میکند.
به عبارتی ModelBinder وظیفه تبدیل دادههای ارسال شده از سمت مرورگر به اشیاء NET. را دارد.
فرض کنید ما مدلی به شکل زیر داریم :
public class CustomerInfo { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public DateTime BirthDate { get; set; } }
فیلد آخر برای ذخیرهی تاریخ تولد مشتری استفاده میشود. که View مربوط به آن به شکل زیر خواهد بود :
همانطور که میبینید تایپ کردن تاریخ به این صورت (1/1/2009 12:00:00 AM) ، هم زیاد جالب نیست و هم کمی مشکل است. به همین دلیل برخی سایتها از سه قسمت جدا برای گرفتن روز ، ماه و سال استفاده میکنند و در نهایت آنها را با یکدیگر ترکیب میکنند.
در این مثال ما نیز میخواهیم تاریخ را به صورت زیر دریافت و پس از تبدیل آن به تاریخ میلادی، آن را به کاربر نمایش دهیم :
اما هنگام ارسال فرم به صورت بالا ، ModelBinder توانایی تبدیل این سه ورودی (روز ، ماه و سال) به فیلد BirthDate موجود در کلاس CustomerInfo را ندارد. به همین خاطر ما باید یک ModelBinder متناسب با نیاز خود را طراحی کنیم.
برای ایجاد یک ModelBinder سفارشی نیاز است که از کلاس IModelBinder ارثبری و متد BindModel آن را پیاده سازی کنیم.
ساختار این اینترفیس به شکل زیر است :
public interface IModelBinder { object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext); }
متد BindModel حاوی 2 پارامتر است :
ControllerContext : حاوی اطلاعاتی در مورد درخواست http جاری
ModelBindingContext : این کلاس حاوی یک property به نام Model است که حاوی ارجاعی به مدلی که همکنون قصد پردازشش آن را دارد.
با توجه به موارد بالا کلاس ما به شکل زیر خواهد بود :
using System; using System.Web; using System.Web.Mvc; using ModelBinderExample.Models; using Persia; namespace ModelBinderExample.CustomModelBinder { // Article written for www.dotnettips.info public class CustomerInfoModelBinder : IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { HttpRequestBase request = controllerContext.HttpContext.Request; string firstName = request.Form.Get("FirstName"); string lastName = request.Form.Get("LastName"); DateTime birthDate = this.GetMiladiDate(request); return new CustomerInfo() { FirstName = firstName, LastName = lastName, BirthDate = birthDate }; } private DateTime GetMiladiDate(HttpRequestBase request) { int day = int.Parse(request.Form.Get("Day")); int month = int.Parse(request.Form.Get("Month")); int years = int.Parse(request.Form.Get("Years")); //Convert shamsi to miladi return Persia.Calendar.ConvertToGregorian(years, month, day, DateType.Gerigorian); } } }
در کد بالا ایتدا موارد ارسال شده را دریافت میکنیم و توسط متد ()GetMiladiDate تاریخ دریافتی از کاربر که به صورت روز، ماه و سال میباشد را تبدیل به میلادی میکنیم و سپس در قالب یک شی customerInfo آنها را برگشت میدهیم.
نکته : جهت تبدیل تاریخ شمسی به میلادی از کتابخانهی Persia کمک گرفته شده است که در فایل پیوستی قرار داده شده.
کار ایجاد یک ModelBinder سفارشی تمام شده و حال نیاز است کلاس را در فایل Global.asax در قسمت ()Application_start ثبت کنیم به شکل زیر :
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); //Register New ModelBinder ModelBinders.Binders.Add(typeof(CustomerInfo), new CustomerInfoModelBinder()); }
و برای استفاده از این ModelBinder ، ما باید به کنترلر اطلاع دهیم که میخواهیم از چه نوع Binding استفاده کنیم به همین دلیل از attribute زیر برای انجام این کار استفاده میکنیم:
[HttpPost] public ActionResult Create([ModelBinder(typeof (CustomerInfoModelBinder))] CustomerInfo customerInfo) { if (ModelState.IsValid) { ViewBag.FirstName = customerInfo.FirstName; ViewBag.LastName = customerInfo.LastName; ViewBag.BirthDate = customerInfo.BirthDate; } return View(); }
پروژه پیوستی : ModelBinder-Example.zip
در قسمت قبل نحوهی اجرای برنامههای ASP.NET را به کمک وب سرور آزمایشی Mono بررسی کردیم. بدیهی است این وب سرور برای هاست کردن سایتها و خدمات دهی عمومی، مناسب نیست و صرفا جهت کارهای برنامه نویسی طراحی شده است. در ادامه، ابتدا وب سرور معروف آپاچی را نصب کرده و سپس سعی خواهیم کرد تا همان دو برنامه ASP.NET Web forms و ASP.NET MVC قسمت قبل را بر روی آن اجرا کنیم (دو برنامه خالی ASP.NET کامپایل شده که از ویندوز به لینوکس کپی شده بودند).
نصب وب سرور آپاچی
به اینترنت متصل شده، ترمینال Ubuntu را گشوده (با میانبر ctrl+alt+t) و سپس فرمانهای ذیل را صادر کنید:
به این ترتیب Apache web server بر روی سیستم نصب خواهد شد.
نصب ماژولهای ASP.NET مخصوص آپاچی
سپس نیاز است ASP.NET runtime for Apache را نصب کنیم:
mod_mono درون پروسه آپاچی اجرا شده و تمام درخواستهای رسیده به یک وب سایت ASP.NET را به mod-mono-server که کار هاست سایت را انجام میدهد، انتقال خواهد داد.
اگر علاقمند به مشاهده تنظیمات آن بودید باید به مسیر etc/apache2/mods-enabled مراجعه کرده و فایل mod_mono.conf را بررسی کنید (اختیاری). برای مثال، در آن حالت اجرا، بر روی ASP.NET 4 تنظیم شدهاست.
تنظیمات آپاچی برای کار با ASP.NET
نیاز است فایل تنظیمات پیش فرض وب سرور آپاچی را جهت معرفی ASP.NET به آن، اندکی ویرایش کنیم:
در ادیتور باز شده، ذیل قسمت ServerAdmin، موارد زیر را اضافه کنید:
در ادامه به المان Directory /var/www سطرهای زیر را اضافه کنید:
المان جدید ذیل را در انتهای فایل اضافه کنید تا یک سری از پوشههای خاص ASP.NET همانند محیطهای ویندوزی در آپاچی نیز محافظت شوند:
فایل را ذخیره کرده و ادیتور را ببندید. اکنون وب سرور آپاچی را اجرا و ری استارت کنید:
همچنین سطح دسترسی مسیر var/www که حاوی برنامههای ما خواهد بود نیز باید تغییر کند:
اکنون اگر آدرس http://127.0.0.1 را در مرورگر وارد کنید، باید پیام «It Works» را مشاهده کنید و اگر خواستید محتوای آنرا ویرایش کنید، دستور ذیل را صادر نمائید:
اجرای مثالها
با تنظیمات فوق، برنامههای کپی شده در مسیر var/www به کمک مونو و آپاچی اجرا خواهند شد.
دسترسیهای فعلی کاربر وارد شده به لینوکس اجازه کپی فایلها را به مسیر var/www نمیدهد. همچنین میخواهیم این کارها را توسط File browser آن انجام دهیم و نه خط فرمان. برای این منظور دستور ذیل را اجرا کنید تا File browser آن با دسترسی مدیریتی اجرا شود:
الان میتوان بدون مشکل در همان File browser گرافیکی آن، پوشه مثال وب فرمهای خود را به درون پوشه var/www کپی کرد.
پس از کپی دو برنامه Web forms و MVC ابتدای بحث، نیاز است مجددا فایل تنظیمات آپاچی را ویرایش کنیم:
اکنون تنظیم برنامه وب فرم را به نحو ذیل به این فایل اضافه کنید:
در تنظیم webforms_test:/var/www/WebFormsApp/، قسمت webforms_test نامی است که در مرورگر وارد خواهد شد و قسمت بعد از : مسیر فایلهای برنامه و ریشه سایت است.
و تنظیم برنامه MVC به صورت زیر میباشد:
بعد از هر بار تغییر فایل تنظیمات آپاچی باید یکبار وب سرور را توسط دستور sudo service apache2 restart ری استارت کنیم.
اکنون برنامه وب فرمها در مسیر http://127.0.0.1/webforms_test و برنامه MVC در مسیر http://127.0.0.1/mvc_test قابل دسترسی است.
خلاصه بحث
پس از نصب وب سرور آپاچی و ماژول مونوی مخصوص آن، فایل etc/apache2/sites-available/default را به نحو ذیل ویرایش کنید و مسیرهای برنامههای خود را در آن تعریف نمائید:
نصب وب سرور آپاچی
به اینترنت متصل شده، ترمینال Ubuntu را گشوده (با میانبر ctrl+alt+t) و سپس فرمانهای ذیل را صادر کنید:
sudo apt-get update sudo apt-get upgrade -y sudo apt-get install apache2
نصب ماژولهای ASP.NET مخصوص آپاچی
سپس نیاز است ASP.NET runtime for Apache را نصب کنیم:
sudo apt-get install libapache2-mod-mono mono-apache-server4
اگر علاقمند به مشاهده تنظیمات آن بودید باید به مسیر etc/apache2/mods-enabled مراجعه کرده و فایل mod_mono.conf را بررسی کنید (اختیاری). برای مثال، در آن حالت اجرا، بر روی ASP.NET 4 تنظیم شدهاست.
تنظیمات آپاچی برای کار با ASP.NET
نیاز است فایل تنظیمات پیش فرض وب سرور آپاچی را جهت معرفی ASP.NET به آن، اندکی ویرایش کنیم:
sudo gedit /etc/apache2/sites-available/default
MonoAutoApplication disabled AddHandler mono .aspx .ascx .asax .ashx .config .cs .asmx .axd MonoApplications "/:/var/www" MonoServerPath default "/usr/bin/mod-mono-server4"
SetHandler mono DirectoryIndex index.aspx index.html default.aspx Default.aspx
<DirectoryMatch "/([bB]in|[Aa]pp_[Cc]ode|[Aa]pp_[Dd]ata|[Aa]pp_[Gg]lobal[Rr]esources|[Aa]pp_[Ll]ocal[Rr]esources)/"> Order deny,allow Deny from all </DirectoryMatch>
sudo service apache2 restart
# r,w,exec for user + group sudo chgrp -R www-data /var/www sudo chown -R www-data /var/www sudo chown -R www-data:www-data /var/www sudo chmod -R 755 /var/www
gedit /var/www/index.html
اجرای مثالها
با تنظیمات فوق، برنامههای کپی شده در مسیر var/www به کمک مونو و آپاچی اجرا خواهند شد.
دسترسیهای فعلی کاربر وارد شده به لینوکس اجازه کپی فایلها را به مسیر var/www نمیدهد. همچنین میخواهیم این کارها را توسط File browser آن انجام دهیم و نه خط فرمان. برای این منظور دستور ذیل را اجرا کنید تا File browser آن با دسترسی مدیریتی اجرا شود:
sudo nautilus
پس از کپی دو برنامه Web forms و MVC ابتدای بحث، نیاز است مجددا فایل تنظیمات آپاچی را ویرایش کنیم:
sudo gedit /etc/apache2/sites-available/default
AddMonoApplications default "/webforms_test:/var/www/WebFormsApp/" <Location /webforms_test> SetHandler mono </Location>
و تنظیم برنامه MVC به صورت زیر میباشد:
AddMonoApplications default "/mvc_test:/var/www/Mvc4ProjectApp/" <Location /mvc_test> SetHandler mono </Location>
اکنون برنامه وب فرمها در مسیر http://127.0.0.1/webforms_test و برنامه MVC در مسیر http://127.0.0.1/mvc_test قابل دسترسی است.
خلاصه بحث
پس از نصب وب سرور آپاچی و ماژول مونوی مخصوص آن، فایل etc/apache2/sites-available/default را به نحو ذیل ویرایش کنید و مسیرهای برنامههای خود را در آن تعریف نمائید:
<VirtualHost *:80> ServerAdmin webmaster@localhost MonoAutoApplication disabled AddHandler mono .aspx .ascx .asax .ashx .config .cs .asmx .axd MonoApplications "/:/var/www" MonoServerPath default "/usr/bin/mod-mono-server4" DocumentRoot "/var/www" <Directory /> Options FollowSymLinks AllowOverride None </Directory> <Directory /var/www/> SetHandler mono DirectoryIndex index.aspx index.html default.aspx Default.aspx Options Indexes Includes FollowSymLinks MultiViews AllowOverride None Order allow,deny allow from all </Directory> ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ <Directory "/usr/lib/cgi-bin"> AllowOverride None Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch Order allow,deny Allow from all </Directory> <DirectoryMatch "/([bB]in|[Aa]pp_[Cc]ode|[Aa]pp_[Dd]ata|[Aa]pp_[Gg]lobal[Rr]esources|[Aa]pp_[Ll]ocal[Rr]esources)/"> Order deny,allow Deny from all </DirectoryMatch> AddMonoApplications default "/webforms_test:/var/www/WebFormsApp/" <Location /webforms_test> SetHandler mono </Location> AddMonoApplications default "/mvc_test:/var/www/Mvc4ProjectApp/" <Location /mvc_test> SetHandler mono </Location> ErrorLog ${APACHE_LOG_DIR}/error.log # Possible values include: debug, info, notice, warn, error, crit, # alert, emerg. LogLevel warn CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>
مطالب
JQuery Plugins #1
جیکوئری به عنوان مهمترین و پرکاربردترین کتابخانه جاوا اسکریپتی، حالا در اکثر سایتهای اینترنتی استفاده میشود و هر روز به قابلیتها و امکانات آن اضافه میگردد. اما بیش از خود این کتابخانه، پلاگینهای آن است که تحول عظیمی را در طراحی وب سایتها ایجاد نموده است. از انواع اسلایدها، تصاویر، منوها، Tooltip ها، نمودارها، انیمیشن، جداول و هزاران پلاگین دیگر، همه و همه کدهای جاوا اسکریپتی است که با استفاده از جی کوئری به صورت پلاگین نوشته شده است و امکان استفاده مجدد را به ما میدهد.
محتوای پلاگین
حفظ خاصیت زنجیرهای پلاگین ها
در پلاگین بالا با از تابع each برای روی this و برگرداندن آن با return برای حفظ خاصیت زنجیرهای پلاگین استفاده مینماییم. در تابع each میبایست از (this)$ برای انجام عملیات بر روی شیء پاس داده شده استفاده کنیم. بدین صورت بعد از صدا زدن پلاگین، دوباره میتوانیم از هر پلاگین یا تابع جی کوئری دیگری بر روی خروجی استفاده نماییم.
از کجا شروع کنیم
برای نوشتن پلاگین یک تابع با نام خاصیتی جدید را به jQuery.fn اضافه مینماییم.
اما، برای اینکه بتوانیم از میانبر $ در پلاگین استفاده نماییم و تداخلی با سایر کتابخانهها نداشته باشد، از الگوی (IIFE (Immediately Invoked Function Expression D به صورت زیر استفاده مینماییم:
jQuery.fn.myPlugin = function() { //محتویات پلاگین را اینجا مینویسیم };
(function( $ ) { $.fn.myPlugin = function() { //محتویات پلاگین را اینجا مینویسیم }; })( jQuery );
محتوای پلاگین
حال میتوانیم در تابع، کدهای پلاگین خود را بنویسیم. برای دسترسی به شیء پاس داده شده به پلاگین، از کلمه کلیدی this استفاده کرده و لازم نیست از (this)$ استفاده نماییم. در زیر یک پلاگین ساده تهیه شده است که با رفتن ماوس بر روی یک متن، خطی زیر آن میکشد:
(function($){ $.fn.underline= function() { this.hover(function(){ $(this).css( { text-decoration : underline }) }, function(){ $(this).css( { text-decoration : none } ) }); }; })(jQuery); $("p").underline();
پلاگین بالا مقدار یا شیء ایی را بر نمیگرداند؛ اما اگر بخواهیم مقداری را برگردانیم از return استفاده مینماییم:
(function( $ ){ $.fn.maxHeight = function() { var max = 0; this.each(function() { max = Math.max( max, $(this).height() ); }); return max; }; })( jQuery );
var tallest = $('div').maxHeight(); // بیشترین ارتفاع عنصر را برمی گرداند
حفظ خاصیت زنجیرهای پلاگین ها
در مثال بالا یک مقدار عددی برگردانده شده است؛ اما برای اینکه بتوانیم بصورت زنجیر وار خروجی پلاگین را به تابع یا هر پالاگین دیگری پاس دهیم از تابع each بصورت زیر استفاده مینماییم:
(function( $ ){ $.fn.lockDimensions = function( type ) { return this.each(function() { var $this = $(this); if ( !type || type == 'width' ) { $this.width( $this.width() ); } if ( !type || type == 'height' ) { $this.height( $this.height() ); } }); }; })( jQuery );
$('div').lockDimensions('width').css('color', 'red');
پیش فرضها و تنظیمات
در پلاگینهای پیشرفتهتر میتوانیم تنظیمات پیش فرضی را برای پلاگین در نظر بگیریم و این تنظیمات را به عنوان پارامتر ورودی از کاربر دریافت نماییم. جی کوئری دارای تابعی به نام extend است که امکان گسترش و ترکیب دو شیء را امکان پذیر میسازد به مثال زیر توجه نمایید:
(function( $ ){ $.fn.tooltip = function( options ) { var settings = $.extend( { 'location' : 'top', 'background-color' : 'blue' }, options); return this.each(function() { // Tooltip plugin code here }); }; })( jQuery );
$('div').tooltip({ 'location' : 'left' });
در این مثال، شیء settings با دو خاصیت location و background-color تعریف شده که با شیء options که از ورودی پلاگین دریافت نمودهایم با استفاده از تابع extend ترکیب شده است. خاصیتهای که تعیین نشده باشند با مقادیر پیش فرض آنها تکمیل میگردد.
ادامه دارد...
اشتراکها
تحریم شکن بگذر!
یک نکتهی تکمیلی
هدر upgrade-insecure-requests از Chrome 83 (June 2020) به بعد حداقل در مورد فایلهای دریافتی از سایتها به صورت خودکار اعمال میشود.