کتابخانه extended ef هم به نظر در این مورد جالب است.
ضرورت استفاده از یک سیستم کنترل نسخه:
در طول روند تولید یک برنامه، چه به صورت تیمی و یا حتی انفرادی، بارها برای برنامه نویسان این نیاز پیش میآید که به نسخههای قدیمیتر فایلهای خود دسترسی داشته باشند تا بتوانند آنچه را که در قبل نوشتهاند مورد بازبینی قرار دهند. شاید کسانی که با سیستمهای مدیریت نسخه آشنایی ندارند، این کار را با استفاده از copy و paste کردن فایلها در پوشههای جداگانه انجام دهند؛ اما روند توسعه یک برنامه در محیط عملی، امکان استفاده از چنین روشی را به ما نمیدهد. زیرا مدیریت این فایلها علی الخصوص در پروژههای تیمی، بعد از مدتی بسیار دشوار خواهد شد. بنابراین نیاز به سیستمی احساس میشود که بتواند این کار را به صورت خودکار انجام دهد.
وظیفه اصلی یک سیستم مدیریت کد، ایجاد یک رویه خودکار جهت دنبال کردن تغییرات فایلهای ما است به طوری که بگوید هر فایل در چه زمانی، توسط چه کسی، به چه دلیل، چه تغییراتی کرده است.
آشنایی با Git:
Git توسط سازنده سیستم عامل لینوکس یعنی آقای Linus Torvalds و برای مدیریت کدهای آن ساخته شد که بعدها توسط Linux-BitKeeper ارتقا یافت. BitKeeper یک سیستم مدیریت کد توزیع شده است که البته رایگان نیست. تیم BitKeeper در ابتدا پروژه لینوکس را به صورت رایگان پشتیبانی میکرد اما در سال 2005 این حمایت را قطع کرد. در این هنگام تیم توسعه لینوکس تصمیم گرفت که خود یک سیستم مدیریت کد توزیع شده ایجاد کند. آنها این سیستم را با Perl و C نوشتند و آن را برای اجرا شدن بر روی انواع سیستم عاملها نظیر لینوکس ویندوز و حتی مک آماده کردند اهداف اصلی Git عبارتند از:
1) سرعت بالا
2) سادگی
3) قدرت پشتیبانی بالا از Merge/Branching
4) یک سیستم کاملا توزیع شده
5) قابلیت توسعه برای پروژههای بزرگ
تفاوت سیستمهای متمرکز و توزیع شده:
سیستمهای کنترل نسخه را میتوان بر اساس خصوصیات مختلف در دستههای متفاوتی قرار داد اما از نظر معماری سیستم, به دو دستهی زیر تقسیم میشوند :
۱) (VCS (Version Control System –سیستمهای مدیریت نسخه متمرکز
۲) (DVCS (Distributed Version Control System- سیستمهای مدیریت نسخه توزیع شده
در ادامه مقاله تفاوت این دو روش را بیان خواهیم نمود و به بررسی مزایا و معایب آنها خواهیم پرداخت
تعریف Repository:
مخزن یا همان Repository محلی است که یک سیستم مدیریت نسخه از آن برای نگهداری تغییرات فایلها استفاده میکند. در سیستمهای VCS این مخزن به صورت متمرکز یا اصطلاحا Centralized Repository میباشد. به این معنا که یک Repository بر روی یک ماشین، خواه سیستم خود برنامه نویس(در پروژههای انفرادی) و خواه یک سرور قرار دارد (در پروژههای تیمی) و برنامه نویسان تغییرات فایلهای خود را به سمت این سرور میفرستند و این سرور وظیفه نگهداری تمامی نسخهها و اطلاعات مربوطه از برنامه نویسان مختلف را به عهده دارد. اشکال این روش در این است که برنامه نویس تنها به نسخه جاری که بر روی سیستم خود است دسترسی دارد و اگر بنا به دلیلی بخواهد از نسخههای پیشین استفاده کند باید آن را از سرور بخواهد که این کار مشکل دیگری ایجاد میکند و آن این است که ممکن است برنامه نویس همیشه در موقعیتی نباشد که بتواند به سرور دسترسی داشته باشد. به همین دلیل این روش وابستگی زیادی برای برنامه نویس ایجاد میکند اما پیاده سازی این روش آسانتر از مدل توزیع شده است.
در مدل توزیع شده علاوه بر یک مخزن که بر روی یک سرور قرار داد و تمامی نسخهها در آن جا نگهداری میشود، هر برنامه نویس یک نسخه محلی مخزن را نیز در اختیار دارد. به این ترتیب وابستگی برنامه نویس به سرور کاهش مییابد؛ همچنین میتوان با ایجاد SubRepositoryها یک ساختار درختی ایجاد نمود که هر کدام از این زیر سیستمها در نهایت اطلاعات را در سرور اصلی قرار میدهند. علاوه بر این به دلیل ساختار توزیع شده، امکان بک آپ گیری در این روش مطمئنتر است. زیرا تنها وابسته به یک سرور نیست و میتواند بر روی سیستمهای مختلف توزیع شده باشد. البته از اشکالات این روش پیچیدگی پیاده سازی بیشتر آن نسبت به سیستمهای متمرکز است.
اما سوال این جا است که ما حقیقتا چه چیزی را باید ذخیره کنیم ؟
پاسخ به این سوال بسیار ساده است: هر آنچه برای ما مهم است که این شامل فایلهای کد, فایلهای پیکربندی, خروجیهای نظیر dll و غیره است. البته در این بین استثنائاتی نظیر فایلهای EXE و یا پکیجهای نصب شده وجود دارد که در بسیاری از موارد نیازی به پیگیری نسخههای آنها نیست اما تمامی اینها وابسته به نظر برنامه نویس است.
در ادامه مقالات ما به تعاریف مورد نیاز در سیستمهای مدیرت کد, ساختار Git و چگونگی نصب و استفاده آن خواهیم پرداخت.
از زمان ارائه نگارش net core 2.1.، ابزارهای سراسری (Global tools) نیز معرفی شدند. استفاده از این ابزارها در محیط cli در جهت آسانتر شدن و سریعتر شدن وظایف، صورت میپذیرد. net core sdk. مربوطه، تمامی امکانات لازم از جهت ایجاد، حذف و به روزرسانی ابزارها را از طریق nuget شامل میگردد. تعداد بسیار زیادی از این ابزارها در حال حاضر ایجاد شدهاند که در لیست زیر، تعدادی از آنها را معرفی میکنیم و سپس به نحوهی ایجاد این نوع ابزارها میپردازیم.
سوییچ g به معنای نصب سراسری ابزار و افزوده شدن آن به متغیرهای محیطی PATH میباشد که به راحتی در هر مسیری از محیط کنسول در دسترس خواهد بود و به مسیر dotnet/tools/. محدود نخواهد بود.
نحوه به روزرسانی ابزار و ارتقا آن به آخرین نسخه پایدار، با دستور زیر میباشد:
دستور حذف:
گزینه PackAsTool، امکان تبدیل فایل اجرایی شما را به یک ابزار سراسری فراهم میکند. دو گزینه بعدی که اختیاری است، به ترتیب شامل نام ابزار سراسری است که در صورت ذکر نشدن نام فایل پروژه، بدون پسوند csproj. میباشد و سومین مورد نیز مسیر قرارگیری فایل ابزار سراسری به عنوان یک بسته nuget میباشد.
سوییچ global که در بالاتر نیز توضیح داده شد، باعث نصب سراسری ابزار میگردد و سوییچ add-source که بعد از آن مسیر فایل ابزار، آمده است، به این معنا است که به صورت موقت، این دایرکتوری یا مسیر را به عنوان مخزن nuget شناسایی کرده تا امکان یافتن بسته در آن مسیر مهیا گردد و سپس نام پروژه در پایان ذکر میگردد. در آخر جهت اطمینان از نصب میتوانید ابزار را صدا بزنید:
با توجه به اینکه اصل مطلب گفته در رابطه با ایجاد یک ابزار سراسری در اینجا به پایان میرسد، ولی ایجاد یک ابزار خط فرمانی نیازمند یک سری کدنویسیها جهت ایجاد کامندها و سوییچها و راهنمای مربوط به آن نیز میباشد. بدین جهت کتابخانه زیر را نصب نمایید:
این کتابخانه شامل کلاس هایی جهت ایجاد یک ابزار خط فرمانی راحتتر میباشد.
با مزین کردن کلاس به ویژگی command، این کلاس را یک کامند معرفی کرده و شرحی از کاری که این کامند را انجام میدهد، نیز وارد میکنیم. این شرح بعدا در ابزار تولید شده به عنوان متن راهنما به کار میرود. سپس پراپرتیهایی را که با ویژگی option مزین گشتهاند، به عنوان سوییچ معرفی میکنیم. همچنین میتوان از DataAnotationها نیز جهت اعتبار سنجی نیز استفاده نمود.
در پارامتر این متد، یک اینترفیس با نام IConsole جهت ارتباط با محیط کنسول دیده میشود که در پایان عملیات، پیام «یادداشت ذخیره شد» توسط آن چاپ میگردد. کار این متد به طور خلاصه این است که مسیر اجرایی ابزار جاری را دریافت کرده و سپس در یک دایرکتوری با نام notes، برای هر یادداشت یک فایل ایجاد شده و محتوای دریافتی از کاربر داخل آن قرار میگرد و نام هر فایل، موضوع یادداشتی است که کاربر وارد کردهاست. متد GetBaseDirectory که مسیر ذخیره یادداشتها را بر میگرداند، در کلاس BaseClass با محتوای زیر قرار گرفته است:
کار این کلاس، بازگردانی لیستی از یادداشتهای ثبت شده است که حاوی سوییچ grep برای فیلتر کردن اسامی یادداشت هاست.
در صورتیکه یادداشت مورد نظر وجود نداشته باشد، با پیام The Note NotFound کار به پایان میرسد.
از آنجا که کلاس Program نیز به ویژگی command مزین شدهاست، متد OnExecute را اضافه میکنیم. تنها تفاوت این متد با متدهای قبلی، در نوع خروجی آن است که هر مقدار غیر از صفر، به منزله خطا میباشد. در این حالت چون کاربر کامندی را صادر نکرده است، ابتدا به کاربر اجباری بودن کامند را گوشزد کرده و سپس از طریق متد ShowHelp، راهنمای کار با ابزار را به او نشان داده و سپس کد یک را به منزله رخ دادن خطا یا اعلام شرایط غیرعادی بازمیگردانیم. نوع خروجی متد OnExecute در صورتی که void باشد، به معنای مقدار 0 میباشد که در کلاسهای قبلی از آن استفاده کردهایم.
تکه کد CommandLineApplication.Execute آرگومانهای ورودی را دریافت کرده و کامند مورد نظر را شناسایی میکند و همچنین مقدار عددی که از آن جهت return شدن استفاده میکند، همان عددهای صفر و غیر صفر میباشد که در بالا توضیح داده شده است.
در ابزار بالا کامند new-note به صورت جدا از هم با خط تیره مشخص شدهاست. دلیل این امر نیز جداشدن این کلمات در نام کلاس با حروف بزرگ است. در صورتیکه قصد ندارید نام کامندها با خط تیره از هم جدا شوند، باید نام کلاس را از NewNote به Newnote تغییر دهید.
- dotnet-ignore : این ابزار جهت دریافت فایلهای gitignore. کاربرد داشته و از یک مخزن عمومی گیت هاب جهت دریافت این فایلها استفاده میکند. این مخزن شامل انواع قالبهای gitignore در پروژههای متفاوت میباشد. با استفاده از این ابزار، ایجاد فایل gitignore راحتتر و سریعتر امکانپذیر میباشد.
- dotnet-serve : میزبانی و نمایش لیست فایلهای استاتیک محلی و اجرای آنها را در بستر http، فراهم مینماید.
- dotnet-cleanup : جهت پاکسازی محیط بیلد مانند دایرکتوریهای bin و obj میباشد. همان کار گزینه clean در منوی بیلد را بازی میکند.
- dotnet-warp : این ابزار در واقع پروژه Warp است که برای ایجاد یک تک فایل اجرایی جهت انتقال راحتتر فایل پروژه صورت میگیرد که همه وابستگیهای آن در همان تک فایل قرار میگیرد.
- Amazon.ECS.Tools , Amazon.ElasticBeanstalk.Tools و Amazon.Lambda.Tools : این ابزارها که به صورت رسمی از طرف آمازون ارائه شدهاند که جهت deploy شدن راحتتر پروژه به محیطهای توسعه وب آمازون مورد استفاده قرار میگیرند.
جهت مشاهده لیست کامل این ابزارها، به این مخزن گیت هاب مراجعه نمایید. نام ابزار و همچنین لینکها و توضیحات هر کدام، در این مخزن موجود است. همچنین جهت اضافه شدن ابزاری که در لیست نیست، از طریق ایجاد issue یا pull request لیست را به روزرسانی نمایید.
نحوهی نصب، حذف و به روزرسانی ابزارهای سراسری
جهت نصب یک ابزار، از دستور زیر استفاده میکنیم:
dotnet tool install -g dotnet-ignore
جهت مشاهده لیست تمامی ابزاهای سراسری نصب شده بر روی سیستم میتوانید از کامند زیر استفاده نمایید:
dotnet tool list -g
dotnet tool update -g dotnet-ignore
dotnet tool uninstall -g dotnet-ignore
ایجاد یک ابزار سراسری
جهت ساخت یک ابزار سراسری نیاز است تا یک پروژه را از نوع کنسول ایجاد نمایید و سپس به فایل csproj، خطوط زیر را اضافه کنید:
<PropertyGroup> <PackAsTool>true</PackAsTool> <ToolCommandName>dotnet-mytool</ToolCommandName> <PackageOutputPath>./nupkg</PackageOutputPath> </PropertyGroup>
جهت ساخته شدن فایل، ابتدا یکبار پروژه را بیلد کرده و پس از اجرای دستور dotnet pack، فایل پکیج در مسیر ذکر شده ساخته میشود و آماده انتقال به مخازن nuget میباشد. جهت تست و اجرای ابزار بر روی سیستم خود قبل از عرضه نهایی نیاز است تا با دستور زیر آن را بر روی سیستم خود نصب و آزمایش نمایید:
dotnet tool install --global --add-source ./nupkg globaltools
dotnet-mytool
https://www.nuget.org/packages/McMaster.Extensions.CommandLineUtils
ایجاد یک ابزار عمومی جهت یادداشت نویسی
برای استفاده از این کتابخانه، یک پروژه از نوع کنسول را با نام globaltools ایجاد نمایید و کتابخانهی بالا را نصب نمایید. سپس به ازای هر کامند، یک کلاس را ایجاد میکنیم. ابتدا جهت ایجاد کامندی با نام NewNote یک کلاس را به همین نام میسازیم:
[Command(Description="Add a new note")] public class NewNote { [Required] [Option(Description="title of note")] public string Title{ get; set; } [Option(Description="content of note")] public string Body{ get; set; } }
بعد از ایجاد موارد بالا، نیاز است که اکشنی که باید این کامند را اجرا کند، به آن اضافه کرد. جهت افزودن این اکشن، یک متد را با نام OnExecute، به بدنه این کلاس اضافه میکنیم:
[Command(Description="Add a new note")] public class NewNote:BaseClass { [Required] [Option(Description="title of note")] public string Title{ get; set; } [Option(Description="content of note")] public string Body{ get; set; } public void OnExecute(IConsole console) { var dir = GetBaseDirectory(); if(!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } var filePath = Path.Combine(dir, Title + ".txt"); File.WriteAllText(filePath, Body); console.WriteLine("the note is saved"); } }
public class BaseClass { protected string GetBaseDirectory(){ var baseDirectory = Environment.CurrentDirectory; return (Path.Combine(baseDirectory, "notes")); } }
کامند بعدی، لیست یادداشتهای ثبت شدهاست:
public class List:BaseClass { [Option(Description="search a phrase in notes title")] public string Grep{ get; set; } public void OnExecute(IConsole console) { try { var baseDirectory = GetBaseDirectory(); var dir = new DirectoryInfo(baseDirectory); var files = dir.GetFiles(); foreach(var file in files) { if(!String.IsNullOrEmpty(Grep) && !file.Name.Contains(Grep)) continue; console.WriteLine(Path.GetFileNameWithoutExtension(file.Name)); } } catch (Exception e) { console.WriteLine(e.Message); } } }
کلاس بعدی show نیز جهت نمایش کلاس بر اساس عنوان یادداشت است:
[Command(Description="show contnet of note")] public class Show:BaseClass { [Required] [Option(Description="title of note")] public string Title{ get; set; } public void OnExecute(IConsole console){ var baseDirectory = GetBaseDirectory(); var file = Path.Combine(baseDirectory, Title+".txt"); if(!File.Exists(file)) { console.WriteLine("The Note NotFound..."); return; } console.WriteLine(File.ReadAllText(file)); } }
بعد از اتمام کامندهای مربوطه، به کلاس program رفته و برای آن نیز ویژگی command را اضافه میکنیم و همچنین ویژگی subCommand را جهت معرفی کامندهایی که در برنامه در دسترس کاربر قرار میگیرند، اضافه میکنیم:
[Command(Description="An Immediate Note Saver")] [Subcommand(typeof(NewNote),typeof(List),typeof(Show))] class Program { static int Main(string[] args) { return CommandLineApplication.Execute<Program>(args); } public int OnExecute(CommandLineApplication app, IConsole console) { console.WriteLine("You must specify a subcommand."); console.WriteLine(); app.ShowHelp(); return 1; } }
در نهایت متد Main را نیز به شکل زیر تغییر میدهیم:
static int Main(string[] args) { return CommandLineApplication.Execute<Program>(args); }
نمونه استفاده از ابزار نهایی
PS D:\projects\Samples\globaltools> dotnet-notes new-note -t "sample1" -b "this is body" the note is saved PS D:\projects\Samples\globaltools> dotnet-notes new-note -t "test1" -b "this is body of another note" the note is saved PS D:\projects\Samples\globaltools> dotnet-notes list sample1 test1 PS D:\projects\Samples\globaltools> dotnet-notes list -g sa sample1 PS D:\projects\Samples\globaltools> dotnet-notes show -t sample1 this is body
نظرات اشتراکها
Upsource 1.0 منتشر شد
این برنامه فقط یک لایه نمایشی حرفهای برای تقریبا تمام مخازن کد معروف مانند Git، SVN، مرکوریال و امثال آن است. بنابراین به خودی خود، مخزن کد نیست.
سؤالی شده به این مضمون : "یه الگوریتم دارم که بر طبق اون باید اعداد تصادفی خیلی بزرگ تولید کنم، اونها رو جمع و ضرب کنم. اینکه چطوری باید از dll یا lib استفاده کنم رو بلد نیستم. از VS2008 استفاده میکنم..."
سؤال در مورد زبان CPP است. کتابخانهی استاندارد انجام اینگونه عملیات برای زبانهای C و CPP ، کتابخانهی OpenSSL است. البته شاید الان 100 کتابخانه دیگر را هم لیست کنید، اما کسانی که با مباحث رمزنگاری اطلاعات مدتی کار کرده باشند، بعید است سر و کارشان به این کتابخانه نیفتاده باشد و یک استاندارد در این زمینه به شمار میرود؛ همچنین به دلیل سورس باز بودن در اکثر سکوهای کاری موجود نیز قابل استفاده است. بنابراین فراگیری نحوهی کار کردن با آن یک مزیت به شمار میرود. قسمتی از این کتابخانهی معظم مرتبط است به کار با اعداد بزرگ. این مورد را هم جهت استفاده در الگوریتم RSA نیاز دارد.
برای استفاده از آن در ویندوز ابتدا باید OpenSSL را کامپایل کنید. کار پر دردسری است. به همین جهت یک سایت فقط به این موضوع اختصاص یافته و هربار آخرین نسخهی OpenSSL را برای ویندوز کامپایل میکند و در اختیار علاقمندان قرار میدهد : +
در حال حاضر یا باید Win32 OpenSSL v1.0.0a و یا Win64 OpenSSL v1.0.0a را دریافت کنید (برنامهی شما اگر 64 بیتی کامپایل شود، dll های 32 بیتی را نمیتواند بارگذاری کند و برعکس).
روش استفاده از کتابخانهی OpenSSL در ویژوال CPP :
الف) ابتدا فایلهای کامپایل شدهی فوق را دریافت و نصب کنید. اکنون برای مثال یک پوشهی OpenSSL-Win32 در کامپیوتر شما با محتویات این کتابخانه باید ایجاد شده باشد(اگر نسخهی 32 بیتی را دریافت کردهاید).
سپس به پوشهی OpenSSL-Win32\lib\VC آن مراجعه کنید. در اینجا فایلهای کتابخانهای جهت استفاده در ویژوال CPP قرار گرفتهاند. اگر از محتویات پوشه OpenSSL-Win32\lib\VC\static استفاده کنید، نیازی به توزیع فایلهای DLL این کتابخانه نخواهید داشت و اگر از کتابخانههای OpenSSL-Win32\lib\VC استفاده کنید، فایلهای dll را نیز حتما باید به همراه برنامهی خود توزیع نمائید.
سه نوع فایل در آن وجود دارند. ختم شده به MD ، MT و MDd که معانی آنها در مورد چند ریسمانی بودن یا خیر است (برگرفته شده از فایل faq.txt دریافتی):
Single Threaded /ML - MS VC++ often defaults to this for the release version of a new project.
Debug Single Threaded /MLd - MS VC++ often defaults to this for the debug version of a new project.
Multithreaded /MT
Debug Multithreaded /MTd
Multithreaded DLL /MD - OpenSSL defaults to this.
Debug Multithreaded DLL /MDd
ب) جهت سهولت کار، پوشهی OpenSSL قرار گرفته در مسیر OpenSSL-Win32\include را در آدرس زیر کپی نمائید:
C:\Program Files\Microsoft Visual Studio 10.0\VC\include
به این صورت حین استفاده از این کتابخانه نیازی به مشخص سازی محل قرارگیری فایلهای include نخواهد بود.
ج) اکنون یک پروژهی جدید Visual C++\Win32\Win32 console application را در VS.NET آغاز کنید؛ برای مثال به نام OpenSSLTest .
د) سپس به منوی پروژه، گزینهی خواص پروژه مراجعه کرده و مطابق تصاویر زیر، این فایلهای کتابخانهای را معرفی کنید (انتخاب MD یا MT یا MDd بر اساس runtime library انتخاب شده است که در تصاویر مشخص گردیده):
ه) اکنون یک مثال ساده در مورد ضرب دو عدد بزرگ به صورت زیر میتواند باشد:
#include "stdafx.h"
#include <openssl/bn.h>
#include <string.h>
void RotateBytes(unsigned char *in, int n)
{
unsigned char *e=in+n-1;
do {
unsigned char temp=*in;
*in++=*e;
*e-- =temp;
} while(in<e);
}
int _tmain(int argc, _TCHAR* argv[])
{
//دو عدد بزرگ جهت آزمایش
unsigned char testP[] = {0xD1,0x31,0x85,0x4D,0x00,0xD6,0x31,0x97,0x3A,0xFC,0xD2,0x27,0x02,0xEF,0xC2,0xA7};
unsigned char testA[] = {0xC7,0x1B,0x25,0x72,0x03,0xCB,0x72,0x03,0xCF,0x23,0x27,0x2D,0x00,0xD6,0x31,0x98};
//تبدیل آرایههای فوق به فرمت اعداد بزرگ
BIGNUM *a = BN_new();
//it should be in "big-endian" form
RotateBytes(testA, 16);
BN_bin2bn(testA, 16, a);
BIGNUM *p = BN_new();
//it should be in "big-endian" form
RotateBytes(testP, 16);
BN_bin2bn(testP, 16, p);
//ضرب این دو عدد در هم
BIGNUM *result = BN_new();
BN_CTX *ctx = BN_CTX_new();
BN_mul(result, a, p, ctx);
//نمایش نتیجه
//حاصل از چند بایت تشکیل شده؟
int num = BN_num_bytes(result);
if(num>0)
{
unsigned char *tmpdata;
if((tmpdata=(unsigned char *)malloc(num)))
memset(tmpdata, 0, num);
//تبدیل عدد با فرمت اعداد بزرگ به آرایهای از بایتها
BN_bn2bin(result, tmpdata);
RotateBytes(tmpdata, num);
for(int i=0; i<num; i++)
{
if(i%16==0) printf("\n");
printf("%02X ",tmpdata[i]);
}
if(tmpdata) free(tmpdata);
}
//آزاد سازی منابع
BN_free(a);
BN_free(p);
BN_CTX_free(ctx);
return 0;
}
در مورد شرح توابع کتابخانه OpenSSL به اینجا مراجع کنید : +
علت استفاده از تابع RotateBytes ، تغییر endian ورودی است.
این سناریو رو در نظر بگیرید:
وب سرور ما در همان محلی قرار دارد که SVN Server نصب شده است.
میخواهیم به ازای هربار Commit تیم به مخزن SVN ما، سایت ارائه شده توسط وب سرور نیز به صورت خودکار به روز شود.
چه باید کرد؟!
احتمالا خیلیها تصور میکنند که امکان پذیر نیست؛ چون مخزن SVN موجود در سرور، ساختار خودش را دارد و همانند فایلهای یک پروژه معمولی نگهداری نمیشود.
برای انجام اینکار چندین روش موجود است، که تمام آنها به مفهوم hooks در SVN گره خورده است. هرچند hook به معنای قلاب است، اما در اینجا معنای تریگر را دارد. شبیه به تریگرهای SQL Server : پیش یا پس از انجام کار یا رخداد مشخصی، فلان کار را انجام بده. (برای اطلاعات بیشتر میتوانید به فصل hooks در این کتابچه مراجعه کنید: (+))
در میان این قلابهای موجود، میتوان از قلاب post-commit جهت به روز رسانی یک سایت پس از هر هماهنگ سازی با مخزن SVN استفاده کرد. پیشنهاد من به تمام کسانی که میخواهند کار با SVN را شروع کنند استفاده از برنامه رایگان Visual SVN Server است. این برنامه سازگاری فوق العادهای با محیط ویندوز دارد (از لحاظ تعریف سطح دسترسیها). همچنین تعریف hooks را هم به شدت ساده کرده است. فقط کافی است روی یک مخزن کد تعریف شده در Visual SVN Server کلیک راست کرده و در برگهی باز شده، تنظیمات سطوح دسترسی یا تعاریف Hooks را اضافه نمود (در اینجا اعمال سطوح دسترسی روی پوشهها یا روی فایلها نیز به همان شکل با کلیک راست و کم و زیاد کردن کاربران میسر است؛ همانند دادن دسترسی بر اساس امکانات NTFS و اکتیودایرکتوری).
بنابراین به صورت خلاصه:
- فرض بر این است که مخزن کد SVN ایی را بر روی سرور راه اندازی کردهاید. همچنین پوشهای را که میخواهید ریشه سایت باشد، مثلا در مسیر دلخواه C:\path\www قرار دارد.
- برای شروع کار، check out باید صورت گیرد. یا میتوان از TortoiseSVN استفاده کرد یا چون مخزن کد در همان سرور است، دستور زیر نیز کار میکند:
svn checkout file:///c:/svn/MyRepository/trunk C:\path\www
- سپس یک فایل bat باید درست کنید با محتوای زیر:
svn update file:///c:/svn/MyRepository/trunk C:\path\www
این فایل bat باید در همان قسمت تعریف post-commit hook استفاده شود.
به این معنا که پس از هر commit ، لطفا مسیر C:\path\www را بر اساس آخرین به روز رسانیهای مخزن کد به صورت خودکار به روز کن. در این حالت اگر فایلی حذف شده باشد، به صورت خودکار از ریشه سایت شما حذف میشود و اگر فایل یا فایلهایی تغییر کرده باشند نیز سریعا به روز رسانی آنها انجام خواهد شد.
در روش svn update ، پوشههای مخفی svn نیز در ریشه سایت حضور خواهند داشت. وجود آنها هم الزامی است زیرا update بر همین اساس کار میکند.
- اگر میخواهید این پوشههای مخفی وجود نداشته باشند از دستور svn export استفاده کنید. فقط دقت کنید که در این حالت اگر فایلی از مخزن کد حذف شده باشد، باز هم در ریشه سایت وجود خواهد داشت. راه حلی هم که توصیه شده، این است که در همان bat فایلی که درست میکنید ابتدا دستور حذف محتویات پوشه ریشه را صادر کنید و بعد svn export . البته بدیهی است این روش نسبت به svn update کندتر است و svn update به شدت بهینه و سریع میباشد.
- یا راه دیگر بجای حذف کردن پوشه موجود و بعد export به آن، استفاده از برنامههایی مانند Robocopy است که میتوانند عملیات همگام سازی را هم انجام دهند. در این حالت محتوای فایل bat شما شبیه به دستورات زیر خواهد شد:
svn checkout file:///c:/svn/MyRepository/trunk C:\temp\Site1 >> output.log
robocopy C:\temp\Site1 C:\path\www *.* /S /XF *.cs *.tmp *.sln *.csproj *.webinfo /XD .svn _svn /PURGE >> output.log
به این معنا که پس از هر commit به مخزن کد (با توجه به تعریف قلاب ذکر شده)، ابتدا یک svn checkout در یک پوشه موقتی (خارج از ریشه اصلی سایت) انجام گردیده و سپس برنامه robocopy یا موارد مشابه آن وارد عمل شده و تغییرات را با ریشه اصلی هماهنگ میکنند (در اینجا میتوان مشخص کرد چه فایلهایی با پسوندهای مشخص، با ریشه سایت هماهنگ نشوند).
در کل همان روش svn update به نظر سریعتر و مقرون به صرفهتر است. اگر از IIS استفاده میکنید، به صورت پیش فرض کسی نمیتواند محتوای پوشهای را با وارد کردن آدرس آن در مرورگر بررسی کند، همچنین IIS فایلهایی را که نمیشناسد (پسوند از پیش تعریف شدهای در بانک اطلاعاتی آن ندارند)، سرو نمیکند و در صورت درخواست آنها، خطای 404 یا "پیدا نشد" به کاربر نهایی ارائه خواهد شد.
به مشکلی در برنامهای برخوردهاید؟ کتابخانهای کار نمیکند؟ خطایی را دریافت کردهاید؟ برنامه کامپایل نمیشود؟ برنامه آنطور که مدنظر شما است رفتار نمیکند؟ برای طرح این مسایل، صرف عنوان کردن «برنامه کار نمیکنه» یا «خطا میده» منزلت خودتان را تا حد یک کاربر عادی تازه کار تنزل دادهاید. در ادامه ساختار یک گزارش خطای خوب را بررسی خواهیم کرد، تا شما را سریعتر به مقصودتان برساند و همچنین کار پیگیری برنامه نویس یا برنامه نویسهای مسئول را نیز مقداری سادهتر کند.
کارهای لازم پیش از طرح سؤال
- سعی کنید انجمنهای مرتبط را یکبار بررسی و جستجو کنید.
- عین خطای دریافتی را در گوگل جستجو کنید. اگر از برنامهها یا کتابخانههای معروف و متداول استفاده میکنید، یکی از مزیتهای مهم کار با آنها، «تنها نبودن» است! یقین داشته باشید خطایی را که دریافت کردهاید پیشتر توسط دهها نفر دیگر در سایتهای مختلف مطرح شدهاند و بالاخره با بررسی آنها میتوان به پاسخ رسید.
- شاید راهنمای برنامه در این مورد خاص مطلبی را عنوان کرده است.
و ... به صورت خلاصه باید بتوانید به این سؤال پاسخ دهید: «خودت چکار کردی؟». حداقل نشان دهید که فرد حاضر و آماده طلبی نیستید و پیشتر یک حداقل تقلایی را انجام دادهاید.
کجا باید سؤال پرسید؟
- اگر به انجمنی برای طرح سؤال خود مراجعه کردهاید، حتما زیر شاخه صحیحی را انتخاب کنید تا سؤال شما بسته نشود یا کلا حذف نگردد. برای مثال سؤال ASP.NET را در بخش سیشارپ نپرسید یا برعکس یا اگر سایتی مقالهای را منتشر کرده، ذیل آن در مورد نحوه بک آپ گرفتن از اکانت توئیتر خود سؤال نپرسید!
- اگر پاسخی را دریافت کردید، ادامه بحث را ذیل همان مطلب پیگیری کنید و مجددا مطلب جدیدی را ایجاد نکنید.
- اگر تا نیم ساعت بعد جوابی را دریافت نکردید، کل بخشهای یک سایت را با ارسال پیام خود اسپم نکنید. یکبار ارسال یک سؤال کافی است. اکثر این سایتها حالت یک «چت آفلاین» را دارند. به این معنا که ابتدا پیغام خود را میگذارید، اگر مدتی بعد (ممکن است چند ساعت بعد) شخصی آنرا مشاهده کرد و قادر به پاسخ دهی بود، به شما کمک خواهد کرد. بنابراین اگر سریعا به جواب نرسیدید، نه کل سایت را اسپم کنید و نه ... شروع به رفتارهای ناشایست کنید. اینکار با فریاد کشیدن وسط یک جمع تفاوتی ندارد. اشخاص مرتبط همواره آنلاین نیستند؛ ضمنا ممکن است واقعا پاسخی برای یک سؤال نداشته باشند. منصف باشید.
- از ایمیلهای خصوصی افراد یا قسمت پیامهای خصوصی سایتها برای ارسال سؤالات شخصی استفاده نکنید. ایمیل خصوصی، مخصوص کارهای شخصی است. قسمت پیامهای خصوصی یک سایت عموما مخصوص رسیدگی به مشکلات کاربری است. این تصور را نداشته باشید که اشخاص مشاور شخصی رایگان پروژههای تجاری شما هستند.
- بهترین محل برای پرسیدن سؤالات مرتبط با یک پروژه خاص، mailing list یا انجمن گفتگو و یا issue tracker آن پروژه است. وقت خودتان را با ارسال خطاهای یک پروژه خاص، در یک انجمن عمومی و همه منظوره تلف نکنید. کمی جستجو کنید که سایت اصلی پروژه کجا است. بعد دقت کنید آیا جایی برای پرسش و پاسخ دارد یا خیر. اکثر پروژههای خوب، مکانی را جهت جمع آوری بازخوردهای پروژه خود، اختصاص میدهند.
چطور باید سؤال پرسید؟
سؤال فنی خوب پرسیدن هم یک هنر است؛ که تعدادی از مشخصههای مهم آنرا در ذیل مرور خواهیم کرد:
- عنوان مناسبی را برای سؤال خود انتخاب کنید. «لطفا کمک کنید» یا «من مشکل دارم» یا «مشکل در پروژه»، عموما واکنشهای تندی را به همراه دارند؛ و تا حد ارسال اسپم در یک سایت بیکیفیت تلقی میشوند. ضمن اینکه انتخاب عنوانهای مناسب، جستجوهای بعدی را در سایت ساده میکنند و کمک بزرگی خواهند بود به افراد بعدی.
- محیطی را که خطا در آن رخ داده است، توضیح دهید. ذکر IIS تنها کافی نیست. کدام نگارش آن؟ در کدام ویندوز؟
برای مثال شماره نگارش کتابخانه یا نرم افزار مورد استفاده را ذکر کنید. شاید خطایی که گرفتهاید در نگارش بعدی آن برطرف شده است.
ذکر شماره نگارش VS.NET یا شماره نگارش دات نت مورد استفاده، سیستم عامل و کلا توصیف محیط بروز خطا، عموما بسیار مفید هستند.
- حتما کل خطای دریافت شده را ارسال کنید. اگر در یک برنامه C خطایی حاصل شود، احتمالا شکلی مانند Error 0xABCD را دارد. اما استثناءهای دات نت به همراه stack trace و حتی شماره سطر خطای حاصل نیز هستند. همین مساله میتواند به خطایابی نهایی بسیار کمک کند.
- سؤال خود را طوری مطرح کنید که شخص مقابل بتواند آنرا در کمترین زمان ممکن «باز تولید» کند. برای مثال ذکر خطای دریافتی بسیار خوب است. اگر دادهای که سبب بروز این خطا شده است را هم ارسال کنید، مفیدتر خواهد بود؛ یا اگر دستور پاور شل خاصی در کنسول نیوگت خطا میدهد، صرفا عنوان نکنید که جواب نگرفتهاید. چه دستوری را اجرا کردهاید؟ چه خطایی را دریافت کردهاید؟ ساختار پروژه شما چیست؟ آیا شخص مقابل میتواند بر اساس اطلاعاتی که ارائه دادید یک آزمایش شخصی را تدارک ببیند؟ آیا میتواند آنرا با توضیحات شما مجددا تولید کند؟
زمان باز تولید خطا را هم مدنظر داشته باشید. برای مثال اگر بتوانید قطعه کدی را ارائه دهید که در کمترین زمان ممکن، صرفا با کپی و پیست آن در VS.NET قابل کامپایل باشد، بسیاری علاقمند به پاسخگویی به شما خواهند شد. در غیراینصورت آنچنان انتظار نداشته باشید که شخص پاسخ دهنده وقت زیادی را برای رسیدگی به جزئیات سؤال شما صرف کند؛ یا مدتی مشغول به تهیه یک مثال جدید بر مبنای توضیحات شما شود.
حجم کدهای ارسالی شما نیز در اینجا مهم هستند. کل پروژه خود را ارسال نکنید! سعی کنید یک مثال کوچک را که بتواند سریعا خطای مدنظر شما را بازتولید کند، ارسال کنید و نه بیشتر. همچنین کدهایی که برای اجرا نیاز به GUI نداشته باشند نیز در این حالت اولویت دارند.
و به صورت خلاصه، خودتان را بجای پاسخ دهنده قرار دهید. آیا با چند جملهای که ارائه دادهاید، میتوان انتظار پاسخی را داشت یا خیر.
- ایمیل شخصی خود را در انتهای پیام ارسال نکنید. کسی اهمیتی نمیدهد! اگر سؤال شما پاسخی داشته باشد، همانجا دریافت خواهید کرد و نه در میل باکس شخصی.
- املاء و انشای متنی را که ارسال میکنید، یکبار بررسی کنید. اگر برای شما اهمیتی ندارد که چه کلمات و جمله بندی را باید بکار برد، برای شخص مقابل هم آنچنان اهمیتی نخواهد داشت که زیاد وقت صرف کند.
- از بکار بردن smileyهای بیش از حد یا قرار دادن تعداد علامت تعجبهای بیش از حد خودداری کنید. این موارد عموما به مسخره کردن شخص مقابل تفسیر میشوند.
- در بدو امر فریاد نکشید که «باگ» پیدا کردهاید؛ خصوصا اگر به mailing list اختصاصی یک پروژه پیامی را ارسال میکنید. چون اگر مشکل شما واقعا باگ نباشد، بیشتر یک توهین تلقی خواهد شد و در دفعات بعدی پاسخ دادن به شما به صورت ضمنی مؤثر خواهند بود؛ یا جواب نمیگیرید و یا جدی گرفته نخواهید شد.
- هدف از کاری را که مشغول به انجام آن بودهاید را نیز ذکر کنید. ذکر خطای دریافتی بسیار مفید است اما اگر بتوانید یک دید کلی را نسبت به کاری که مشغول به آن بودهاید، ایجاد کنید، شاید پاسخ بهتری را دریافت کنید. برای مثال جهت رسیدن به هدف و مقصود شما بهتر است از روش دیگری استفاده کنید.
- پس از اینکه پیامی را دریافت کردید، یک حداقل واکنشی را ارسال کنید. مثلا خوب بود؛ کمک کرد و یا مفید نبود. همین واکنشها در آینده به کمک نتایج جستجوهای انجام شده خواهند آمد و اشخاص بعدی حداقل خواهند دانست که پاسخ داده شده صحیح بوده است یا خیر.
و همیشه بخاطر داشته باشید: تمام خدماتی که سایتهای عمومی به شما ارائه میدهند «یک لطف» است و حقی را برای شما ایجاد نمیکنند. این اشخاص از شما پول نمیگیرند تا به سؤالات شما پاسخ دهند یا تبدیل به مشاور خصوصی رایگان شما شوند. میتوانید محیط را برای این اشخاص، با اندکی احترام، ملایمت و انصاف، دلپذیرتر کنید.
کارهای لازم پیش از طرح سؤال
- سعی کنید انجمنهای مرتبط را یکبار بررسی و جستجو کنید.
- عین خطای دریافتی را در گوگل جستجو کنید. اگر از برنامهها یا کتابخانههای معروف و متداول استفاده میکنید، یکی از مزیتهای مهم کار با آنها، «تنها نبودن» است! یقین داشته باشید خطایی را که دریافت کردهاید پیشتر توسط دهها نفر دیگر در سایتهای مختلف مطرح شدهاند و بالاخره با بررسی آنها میتوان به پاسخ رسید.
- شاید راهنمای برنامه در این مورد خاص مطلبی را عنوان کرده است.
و ... به صورت خلاصه باید بتوانید به این سؤال پاسخ دهید: «خودت چکار کردی؟». حداقل نشان دهید که فرد حاضر و آماده طلبی نیستید و پیشتر یک حداقل تقلایی را انجام دادهاید.
کجا باید سؤال پرسید؟
- اگر به انجمنی برای طرح سؤال خود مراجعه کردهاید، حتما زیر شاخه صحیحی را انتخاب کنید تا سؤال شما بسته نشود یا کلا حذف نگردد. برای مثال سؤال ASP.NET را در بخش سیشارپ نپرسید یا برعکس یا اگر سایتی مقالهای را منتشر کرده، ذیل آن در مورد نحوه بک آپ گرفتن از اکانت توئیتر خود سؤال نپرسید!
- اگر پاسخی را دریافت کردید، ادامه بحث را ذیل همان مطلب پیگیری کنید و مجددا مطلب جدیدی را ایجاد نکنید.
- اگر تا نیم ساعت بعد جوابی را دریافت نکردید، کل بخشهای یک سایت را با ارسال پیام خود اسپم نکنید. یکبار ارسال یک سؤال کافی است. اکثر این سایتها حالت یک «چت آفلاین» را دارند. به این معنا که ابتدا پیغام خود را میگذارید، اگر مدتی بعد (ممکن است چند ساعت بعد) شخصی آنرا مشاهده کرد و قادر به پاسخ دهی بود، به شما کمک خواهد کرد. بنابراین اگر سریعا به جواب نرسیدید، نه کل سایت را اسپم کنید و نه ... شروع به رفتارهای ناشایست کنید. اینکار با فریاد کشیدن وسط یک جمع تفاوتی ندارد. اشخاص مرتبط همواره آنلاین نیستند؛ ضمنا ممکن است واقعا پاسخی برای یک سؤال نداشته باشند. منصف باشید.
- از ایمیلهای خصوصی افراد یا قسمت پیامهای خصوصی سایتها برای ارسال سؤالات شخصی استفاده نکنید. ایمیل خصوصی، مخصوص کارهای شخصی است. قسمت پیامهای خصوصی یک سایت عموما مخصوص رسیدگی به مشکلات کاربری است. این تصور را نداشته باشید که اشخاص مشاور شخصی رایگان پروژههای تجاری شما هستند.
- بهترین محل برای پرسیدن سؤالات مرتبط با یک پروژه خاص، mailing list یا انجمن گفتگو و یا issue tracker آن پروژه است. وقت خودتان را با ارسال خطاهای یک پروژه خاص، در یک انجمن عمومی و همه منظوره تلف نکنید. کمی جستجو کنید که سایت اصلی پروژه کجا است. بعد دقت کنید آیا جایی برای پرسش و پاسخ دارد یا خیر. اکثر پروژههای خوب، مکانی را جهت جمع آوری بازخوردهای پروژه خود، اختصاص میدهند.
چطور باید سؤال پرسید؟
سؤال فنی خوب پرسیدن هم یک هنر است؛ که تعدادی از مشخصههای مهم آنرا در ذیل مرور خواهیم کرد:
- عنوان مناسبی را برای سؤال خود انتخاب کنید. «لطفا کمک کنید» یا «من مشکل دارم» یا «مشکل در پروژه»، عموما واکنشهای تندی را به همراه دارند؛ و تا حد ارسال اسپم در یک سایت بیکیفیت تلقی میشوند. ضمن اینکه انتخاب عنوانهای مناسب، جستجوهای بعدی را در سایت ساده میکنند و کمک بزرگی خواهند بود به افراد بعدی.
- محیطی را که خطا در آن رخ داده است، توضیح دهید. ذکر IIS تنها کافی نیست. کدام نگارش آن؟ در کدام ویندوز؟
برای مثال شماره نگارش کتابخانه یا نرم افزار مورد استفاده را ذکر کنید. شاید خطایی که گرفتهاید در نگارش بعدی آن برطرف شده است.
ذکر شماره نگارش VS.NET یا شماره نگارش دات نت مورد استفاده، سیستم عامل و کلا توصیف محیط بروز خطا، عموما بسیار مفید هستند.
- حتما کل خطای دریافت شده را ارسال کنید. اگر در یک برنامه C خطایی حاصل شود، احتمالا شکلی مانند Error 0xABCD را دارد. اما استثناءهای دات نت به همراه stack trace و حتی شماره سطر خطای حاصل نیز هستند. همین مساله میتواند به خطایابی نهایی بسیار کمک کند.
- سؤال خود را طوری مطرح کنید که شخص مقابل بتواند آنرا در کمترین زمان ممکن «باز تولید» کند. برای مثال ذکر خطای دریافتی بسیار خوب است. اگر دادهای که سبب بروز این خطا شده است را هم ارسال کنید، مفیدتر خواهد بود؛ یا اگر دستور پاور شل خاصی در کنسول نیوگت خطا میدهد، صرفا عنوان نکنید که جواب نگرفتهاید. چه دستوری را اجرا کردهاید؟ چه خطایی را دریافت کردهاید؟ ساختار پروژه شما چیست؟ آیا شخص مقابل میتواند بر اساس اطلاعاتی که ارائه دادید یک آزمایش شخصی را تدارک ببیند؟ آیا میتواند آنرا با توضیحات شما مجددا تولید کند؟
زمان باز تولید خطا را هم مدنظر داشته باشید. برای مثال اگر بتوانید قطعه کدی را ارائه دهید که در کمترین زمان ممکن، صرفا با کپی و پیست آن در VS.NET قابل کامپایل باشد، بسیاری علاقمند به پاسخگویی به شما خواهند شد. در غیراینصورت آنچنان انتظار نداشته باشید که شخص پاسخ دهنده وقت زیادی را برای رسیدگی به جزئیات سؤال شما صرف کند؛ یا مدتی مشغول به تهیه یک مثال جدید بر مبنای توضیحات شما شود.
حجم کدهای ارسالی شما نیز در اینجا مهم هستند. کل پروژه خود را ارسال نکنید! سعی کنید یک مثال کوچک را که بتواند سریعا خطای مدنظر شما را بازتولید کند، ارسال کنید و نه بیشتر. همچنین کدهایی که برای اجرا نیاز به GUI نداشته باشند نیز در این حالت اولویت دارند.
و به صورت خلاصه، خودتان را بجای پاسخ دهنده قرار دهید. آیا با چند جملهای که ارائه دادهاید، میتوان انتظار پاسخی را داشت یا خیر.
- ایمیل شخصی خود را در انتهای پیام ارسال نکنید. کسی اهمیتی نمیدهد! اگر سؤال شما پاسخی داشته باشد، همانجا دریافت خواهید کرد و نه در میل باکس شخصی.
- املاء و انشای متنی را که ارسال میکنید، یکبار بررسی کنید. اگر برای شما اهمیتی ندارد که چه کلمات و جمله بندی را باید بکار برد، برای شخص مقابل هم آنچنان اهمیتی نخواهد داشت که زیاد وقت صرف کند.
- از بکار بردن smileyهای بیش از حد یا قرار دادن تعداد علامت تعجبهای بیش از حد خودداری کنید. این موارد عموما به مسخره کردن شخص مقابل تفسیر میشوند.
- در بدو امر فریاد نکشید که «باگ» پیدا کردهاید؛ خصوصا اگر به mailing list اختصاصی یک پروژه پیامی را ارسال میکنید. چون اگر مشکل شما واقعا باگ نباشد، بیشتر یک توهین تلقی خواهد شد و در دفعات بعدی پاسخ دادن به شما به صورت ضمنی مؤثر خواهند بود؛ یا جواب نمیگیرید و یا جدی گرفته نخواهید شد.
- هدف از کاری را که مشغول به انجام آن بودهاید را نیز ذکر کنید. ذکر خطای دریافتی بسیار مفید است اما اگر بتوانید یک دید کلی را نسبت به کاری که مشغول به آن بودهاید، ایجاد کنید، شاید پاسخ بهتری را دریافت کنید. برای مثال جهت رسیدن به هدف و مقصود شما بهتر است از روش دیگری استفاده کنید.
- پس از اینکه پیامی را دریافت کردید، یک حداقل واکنشی را ارسال کنید. مثلا خوب بود؛ کمک کرد و یا مفید نبود. همین واکنشها در آینده به کمک نتایج جستجوهای انجام شده خواهند آمد و اشخاص بعدی حداقل خواهند دانست که پاسخ داده شده صحیح بوده است یا خیر.
و همیشه بخاطر داشته باشید: تمام خدماتی که سایتهای عمومی به شما ارائه میدهند «یک لطف» است و حقی را برای شما ایجاد نمیکنند. این اشخاص از شما پول نمیگیرند تا به سؤالات شما پاسخ دهند یا تبدیل به مشاور خصوصی رایگان شما شوند. میتوانید محیط را برای این اشخاص، با اندکی احترام، ملایمت و انصاف، دلپذیرتر کنید.
در قسمت قبلی با نحوهی اجرا و ویژگیهای فنی و خصوصیات کدنویسی x-editable آشنا شدیم. غیر از این خصوصیات، خصوصیات دیگری هم هستند که فقط مختص نوع کنترلی هست که در قسمت type مشخص کردهاید.
کنترلهای زیر جهت ورود اطلاعات در ویرایشگر پشتیبانی میشوند:
کنترلهای زیر جهت ورود اطلاعات در ویرایشگر پشتیبانی میشوند:
- text
- textarea
- select
- date
- datetime
- dateui
- combodate
- html5types
- checklist
- wysihtml5
- typeahead
- typeaheadjs
- select2
clear | دکمهای جهت حذف محتوای کادر متنی است. مقدار پیش فرض آن true است. |
escape | برای
دفاع در برابر کدهای مخرب html به کار میرود و کاراکترهای مدنظر را در صورت
true بودن غیرفعال میکند. البته اگر از خاصیت display استفاده کنید این
گزینه تاثیرش را از دست خواهد داد. |
inputclass | یک کلاس css را به کادر متنی اعمال میکند. |
placeholder | مقدار داده شده را در صورتی که کادر متنی خالی باشد، نشان میدهد. |
tpl | به معنی یک قالب. شما میتوانید کد html تگ input خود را وارد کنید؛ ولی توصیه نمیشود. |
TextArea
همان خاصیتهای قبلی را دارد بعلاوه rows که نمایانگر مقدار ارتفاع آن است.
select
خاصیتهای escape,input,class و tpl را دارد بهعلاوه خاصیتهای زیر:
prepend | همانند گزینه پایینی است ولی قبل از آن دادههای خود را اضافه میکند. |
source | از
آنجا که یک لیست، لیستی از آیتمها را دارد و کاربر یکی از آنها را
انتخاب میکند، این بخش، منبع آیتمها را معرفی میکند. این خاصیت چهار نوع
داده میپذیرد: آرایه یا شیءایی از مقادیر. تابعی که بعد از انجام هر عملی،
اطلاعات به آن پاس میشوند و یا از نوع رشته که این رشته یک آدرس سمت سرور
است که با درخواست از آن آدرس، اطلاعات را دریافت میکند. |
sourceCache | اگه خاصیت بالا با آدرسی پر شده باشد که از سمت سرور بخواند، در دفعات بعدی مقدار دریافتی را از کش خواهد خواند. |
sourceError | یک پیام خطا هنگام بارگزاری اطلاعات |
sourceOptions | در
صورتیکه قصد اضافه کردن پارامتری را به درخواست ایجکسی دارید. یک شیء از پارامترها را به آن
نسبت میدهیم و برای رونویسی پارامترها از یک تابع استفاده میکنیم که نحوهی تغییرات را قبلا در جدول شماره یک دیدهاید. |
date
خاصیتهای مشترک قبلی : tpl,input,class,escape و clear است.
datepicker | پیکربندی تقویم را بر عهده دارد. برای اطلاعات بیشتر در مورد پیکربندی تقویم به این لینک مراجعه فرمایید.{ weekStart: 0, startView: 0, minViewMode: 0, autoclose: false } |
format | قالب بندی فرمت تاریخ جهت ارسال به سرور\ حالت پیش فرض yyyy-mm-dd مقادیری که میتوان به کار برد: yy yyyy mm m dd d |
viewformat | این فرمت هنگام نمایش به کار میآید و در صورتیکه مقدار عنصر در این قالب نباشد، آن را تبدیل میکند. |
datetime در بوت استراپ
کاملا مشترک با مورد قبلی.
dateUI
مختص JqueryUI است و کاملا مشترک با مورد قبلی.
combodate
موارد مشترک قبلی را دارد ولی به جای خاصیت datepicker از combodate استفاده میشود که پیکربندی آن در این لینک قرار دارد.
نوعهای HTML 5
شامل موارد زیر است:
- password
- url
- tel
- number
- range
- time
خاصیتهای ذکر شده در مورد نوع text، در مورد آنها نیز صدق میکند.
checklist
همانند نوع select است؛ فقط خاصیت separator را دارد که کارش جدا کردن مقادیر است و مقدار پیش فرض آن علامت ',' است.
wysihtml5
سورس و دمو ی این نوع ادیتور که بر پایهی بوت استرپ بنا شده است و زحمت اضافه کردن کتابخانهها به صفحه، بر عهده شماست.
مداخل زیر را به طور دستی به صفحه اضافه کنید:
<link href="js/inputs-ext/wysihtml5/bootstrap-wysihtml5-0.0.2/bootstrap-wysihtml5-0.0.2.css" rel="stylesheet" type="text/css"></link> <script src="js/inputs-ext/wysihtml5/bootstrap-wysihtml5-0.0.2/wysihtml5-0.3.0.min.js"></script> <script src="js/inputs-ext/wysihtml5/bootstrap-wysihtml5-0.0.2/bootstrap-wysihtml5-0.0.2.min.js"></script>
<script src="js/inputs-ext/wysihtml5/wysihtml5.js"></script>
این فایل در بستهای که دانلود کردهاید موجود است. شامل خاصیتهای escape,inputclass,placeholder,tpl است و خاصیت wysihtml5
شامل تنظیمات و پیکربندی ادیتور است که پیکریندی آن را میتوانید در اینجا مطالعه بفرمایید.
typeahead
این گزینه فقط مختص بوت استرپ 2 است و یک کنترل autocomplete به شمار میآید. منبع دادههای آن از طریق خاصیت source به دو صورت آرایه و object تامین میگردد.
typeahead
این گزینه فقط مختص بوت استرپ 2 است و یک کنترل autocomplete به شمار میآید. منبع دادههای آن از طریق خاصیت source به دو صورت آرایه و object تامین میگردد.
['text1', 'text2', 'text3' ...] //or [{value: 1, text: "text1"}, {value: 2, text: "text2"}, ...]
شامل خاصیتهای clear,escape,prepend,source,sourceOptions,sourceError,sourceCache,inputclass,tpl است و شامل خاصیت typeahead جهت پیکربندی آن میشود.
typeaheadjs
همانند قبلی است و بر اساس twitterBootstrap است و شامل همان خصوصیات قبلی است. تنها خصوصیت typeahead آن است که باید از این پیکربندی استفاده کنید.
Select2
این المان بر اساس این کتابخانه سورس باز ایجاد میشود. و مستندات آن شامل جزئیات و پیکربندی آن میشود. برای معرفی آن فایلهای زیر را به صفحه معرفی کنید.
typeaheadjs
همانند قبلی است و بر اساس twitterBootstrap است و شامل همان خصوصیات قبلی است. تنها خصوصیت typeahead آن است که باید از این پیکربندی استفاده کنید.
Select2
این المان بر اساس این کتابخانه سورس باز ایجاد میشود. و مستندات آن شامل جزئیات و پیکربندی آن میشود. برای معرفی آن فایلهای زیر را به صفحه معرفی کنید.
<link href="select2/select2.css" rel="stylesheet" type="text/css"></link> <script src="select2/select2.js"></script>
<link href="select2-bootstrap.css" rel="stylesheet" type="text/css"></link>
نکته: در حال حاضر خاصیت autotext روی این المان جواب نمیدهد و میتوانید از خاصیت data-value به جای آن استفاده کنید.
شامل خاصیتهای inputclass , escape , placeolder , source , tpl میباشد و از select2 برای دریافت پیکربندیهای کنترل استفاده میکند و علامت جدا کننده آن توسط viewseperator صورت میگیرد.
قالبی نو برای ویرایشگر
ویرایشگر فعلی ما به خصوص در بوت استرپ، ظاهر فوق العادهای دارد. ولی اگر بازهم مایل به تغییر و رونویسی هستید، این امکان فراهم شده است.
fn.editableform.template$
مقدار پیش فرض آن که حتما باید شامل تگ فرم و کلاسهای مدنظر باشد:
در صورتی که قصد تغییر کلاسهای آن را دارید باید کلاسهای زیر را رونویسی کنید:
قالبی نو برای ویرایشگر
ویرایشگر فعلی ما به خصوص در بوت استرپ، ظاهر فوق العادهای دارد. ولی اگر بازهم مایل به تغییر و رونویسی هستید، این امکان فراهم شده است.
fn.editableform.template$
مقدار پیش فرض آن که حتما باید شامل تگ فرم و کلاسهای مدنظر باشد:
<form> <div> <div><div></div><div></div></div> <div></div> </div> </form>
- control-group
- editable-input
- editable-buttons
- editable-error-block
fn.editableform.buttons$
<button type="submit">ok</button> <button type="button">cancel</button>
و نهایتا جهت تغییر loading
fn.editableform.loading$
<div></div>
گاهی اوقات نیاز است که خصوصیات این ویرایشگر را در شرایط متغیر صفحه کنترل کنیم، برای مثال گاهی پیش میآید که بخواهید در یک شرایط خاص ویرایشگر یک المان خاص را غیرفعال کنید. کد زیر مثال این تغییرات است.
$('#favsite').editable('option', 'disabled', false);
متدها و رویدادها
متدهایی که روی آن قابل اجراست:
editable | ویرایشگر را بر اساس مقادیر اولیه روی عنصر مشخص شده فعال میکند. |
() activate | فوکوس را به input ویرایشگر باز میگرداند. |
() destory | حذف ویژگی ویرایش از روی عنصر |
() disable | غیرفعال کردن ویرایشگر |
() enable | فعال سازی آن |
()getvalue | باعث بازگردانی
مقدار جاری همه عناصر توسط شیء جفت کلید مقدار میشود و عناصری که شامل
متن یا مقداری نیستند، از آن حذف میشوند. در صورتیکه قصد دارید مقدار تنها
یک عنصر قابل دریافت باشد، با خاصیت isSingle آن را true کنید. $('#username, #fullname').editable('getValue'); //result: { username: "superuser", fullname: "John" } //isSingle = true $('#username').editable('getValue', true); //result "superuser" |
()hide | مخفی کردن تگ فرم ویرایشگر |
(option(key,value | تغییر خصوصیات یک عنصر که در بالا هم نمونه کد آن را دیدیم. |
(setvalue(value,convertStr | ست کردن مقدار جدید کنترل و پارامتر دوم وضعیت تبدیل این مقدار به فرمت داخلی است که برای آن تعریف شده است مثل date |
() show | نمایش ویرایشگر |
( submit(options | در
صورتی که خاصیت ارسال خودکار به سمت سرور را غیر فعال کرده باشید، با این
گزینه میتوانید همه اطلاعات و تغییرات را ارسال کنید. برای ایجاد فرم بر
اساس ویرایشگرها و ارسال اطلاعات با کلیک بر روی دکمه submit کاربرد دارد. یک مثال
در این زمینه . پارامترهای options به شرح زیر هستند: url data ajaxoptions (error(obj (success(obj,config از نسخه 1.5.1 میتوان این گزینه را به راحتی روی یک المان خاص هم صدا زد: $('#username').editable('submit') |
() toggle | کدی که صدا زده میشود بین دو وضعیت show و hide سوئیچ میکند. |
() toggleDisabled | تغییر وضعیت بین دو حالت enable و disable |
() validate | انجام اعتبارسنجی بر روی همه کنترل ها.$('#username, #fullname').editable('validate'); // possible result: { username: "username is required", fullname: "fullname should be minimum 3 letters length" } |
رویدادها
hidden | این
رویداد زمانی رخ میدهد که ویرایشگر دیگر قابل مشاهده نیست و شامل دو پارامتر
event و reason است. reason دلیل اینکه چرا ویرایشگر از دید خارج شده است
را با یکی از گزینههای زیر مشخص میکند. save cancel onblur nochange manual $('#username').on('hidden', function(e, reason) { if(reason === 'save' || reason === 'cancel') { //auto-open next editable $(this).closest('tr').next().find('.editable').editable('show'); } }); |
init | موقعی صدا زده میشود که متد editable روی عنصر صدا زده میشود و به یاد داشته باشید که این رویداد باید قبل از آن ست شده باشد.$('#username').on('init', function(e, editable) { alert('initialized ' + editable.options.name); }); $('#username').editable(); |
save | موقعی
که مقدار جدید، با موفقیت تایید میشود. دو پارامتر event و params را باز
میگرداند که params شامل دو خصوصیت newValue و response است که به ترتیب
مقدار جدید و اطلاعات برگشت داده شده از درخواست آژاکس است.$('#username').on('save', function(e, params) { alert('Saved value: ' + params.newValue); }); |
shown | موقعیکه ویرایشگر نمایش مییابد و فرم با موفقیت رندر شده است. برای اشیایی چون select باید صبر کنید تا مقادیر آنها بارگذاری شوند.$('#username').on('shown', function(e, editable) { editable.input.$input.val('overwriting value of input..'); }); |
حل مشکل این ابزار در کندو
موقعیکه من این ابزار را بر روی treeview قرار دادم، به این مشکل برخوردم که اطراف پنجره باز شده، توسط حاشیههای treeview محدود شده است و مطابق شکل زیر قسمتهایی از آن دیده نمیشود. به همین علت cssهای کندو را به اندازه یک خط ویرایش کردم.
برای حل این مشکل فایل kendo.common-xxx را باز کنید. xxx بر اساس قالبی که برای کندو انتخاب کردهاید، میتواند متفاوت باشد. در مثالهای کندو عموما این xxx به نام default شناخته میشود یا برای مثال من، bootstrap بود.
بعد از اینکه باز کردید، به دنبال چنین استایلی بگردید:
div.k-treeview{ border-width: 0px; background: transparent none repeat scroll 0px center; overflow: auto; white-space: nowrap; }
overflow: auto;
نکته بعدی اینکه وقتی ویرایشگر در حالت popup قرار میگیرد، مقدار خاصیت title نمایش مییابد که عموما با مضامینی چون "کلمه جدید را وارد نمایید" و ... پر میشود که به طور پیش فرض سمت چپ قرار گرفته است. کد زیر را در صفحه وارد کنید تا متن در سمت راست قرار بگیرد:
.popover-title { text-align: right; }
شخصی سازی using directives
موقعی که یک کلاس جدید را در VS.NET باز میکنید، فضاهای نامی مشخص و تکراری، همیشه به صورت پیش فرض صدا زده شدهاند و این فضاهای نام را مایکروسافت بر اساس بیشترین کاربرد و استفاده توسط برنامه نویسان قرار داده است؛ ولی در خیلی از اوقات این فضاهای نام پیش فرض، چنان هم برای خیلی از برنامه نویسان کاربردی نداشته یا با توجه به برنامه هایی که مینویسند همیشه متفاوت هست و هربار مجبورند فضاهای نام خاصی را صدا بزنند. برای مثال فضای نام System.ComponentModel.DataAnnotations را در نظر بگیرید که برنامه نویس میخواهد برای مدلهای نوشته شده خود از تگهای متا استفاده کند و باید در هرکلاس ساخته شده، یکبار مورد بالا را صدا بزند که بیشتر باعث کند شدن کار برنامه نویس میشود. پس باید کاری کنیم که پیش فرضهای فضای نام به آنچه خودمان میخواهیم تغییر پیدا کند.
برای این منظور، به محل نصب ویژوال استودیو رفته و مسیر زیر را دنبال کنید (به مسیر دقت کنید ،در اینجا زبان سی شارپ انتخاب شده است):
X:\...\IDE\ItemTemplates\CSharp\Code\1033
در اینجا تعدادی دایرکتوری با اسامی آشنا میبینید که داخل هر کدام از آنهای یک فایل به اسم class.cs هست و اگر آن را باز کنید یک نمونه یا قالب برای usingها قابل مشاهده است. برای مثال ما وارد دایرکتوری class میشویم و فایل class.cs را باز میکنیم:
using System; using System.Collections.Generic; $if$ ($targetframeworkversion$ >= 3.5)using System.Linq; $endif$using System.Text; $if$ ($targetframeworkversion$ >= 4.5)using System.Threading.Tasks; $endif$ namespace $rootnamespace$ { class $safeitemrootname$ { } }
یک سری از فضاهای نام که در تمامی فریمورکها استفاده میشوند به همان شکل عادی نوشته شدهاند. ولی آنهایی که از نسخهی خاصی از یک فریم ورک اضافه شدهاند باید توسط شرط مورد نظر اضافه شده و اعلام شود که این فضای نام از چه نسخهی فریم ورکی به بعد باید اضافه گردد:
$if$ ($targetframeworkversion$ >= 3.5)using System.Linq;//فضای نام مورد نظر $endif$
حال در همان دایرکتوری سی شارپ دقت کنید، میبینید که برای موارد دیگری هم فایل هایی وجود دارند. برای مثال برای اینترفیسها یا silverlight و ... که هر کدام را میتوانید جداگانه تغییر دهید.
نکته:احتمال دارد در نسخههای متفاوت به خصوص پایینتر مثل نسخه 8 ویژوال استودیو ، فایل class.cs به صورت zip باشد که بعد از تغییرات باید دوباره به حالت zip بازگردانده شود.
حذف فضای نامهای اضافی
هر موقع که کلاس جدیدی میسازیم، namespaceها به صورت پیش فرض که در بالا اشاره کردیم وجود دارند و شاید اصلا در آن کلاس از آنها استفاده نمیکنیم یا حتی خودمان در حین نوشتن کدها چند namespace خاص را اضافه میکنیم که شاید در طول برنامه نویسی چندتایی را بلا استفاده بگذاریم. برای همین همیشه فضای نام هایی صدا زده شدهاند که اصلا در آن کلاس استفاده نشدهاند. پس برای همین بهتر هست که این رفرنسهای بلا استفاده را پیدا کرده و آنها را حذف کنیم.
شاید این سوال برای بعضیهای پدید بیاد که چرا باید اینها را حذف کنیم، چون کاری هم با ما ندارند و ما هم کاری با آنها نداریم؟
این کار چند علت میتواند داشته باشد:
- تمیزکاری کد و خلوت شدن فضای کدنویسی
- ممکن هست بعدها گیج کننده شود که من چرا از اینها استفاده کردم؟ در آینده با نگاه به یک کد تمیزتر متوجه میشوید یک کد از چه چیزهایی برای انجام کارش بهرهمند شده و هم اینکه در کارهای گروهی و تیمی هم این مورد به شدت تاثیرگذار هست.
- باعث کند شدن تحلیلهای ایستا میشه (اینجا و اینجا )
- کمپایل شدن کد کندتر میشه
- موقع تست برنامه، اجرای اولیه کندتر خواهد بود چون CLR باید این نوع موارد را شناسایی و حذف کند
برای حذف فضاهای نام اضافی در یک صفحه میتوانید از طریق این مسیر انجام بدید:
Edit>IntelliSense >Organize Usings>Remove Unused using
برای مرتب سازی هم گزینه Sort Usings و انجام هر دو کار Remove and Sort موجود هست.
البته اگه روی صفحه هم راست کلیک کنید گزینه Organize Usings هم وجود دارد.
می توانید از ابزارهایی چون Power tools Extensions هم استفاده کنید (در صورتی که ویژوال استودیوی شما گزینههای مورد نظر را ندارد، این ابزار را نصب نمایید)
در صورتی که از ابزارهایی چون telerik یا devexpress استفاده میکنید یا از هر ابزار اضافی که بر روی IDE نصب میشود، عموما چنین گزینه هایی حتی با امکانات وسیعتر وجود دارند. مثلا whole tomato هم یکی از این ابزارهاست.
این نکته را هم خاطر نشان کنم در صورتیکه فضاهای نامی بین پیش پردازنده ها که در قبل توضیح دادیم محصور شده باشند، حذف نخواهند شد و همانطور باقی خواهند ماند.
در مورد کامنتهای بین usingها به قطعه کد زیر نگاه کنید:
using System; /* Comment before remains */ using /* Comment between removed */ System.Linq; // Comment after remains namespace ConsoleApplication1 { class Program { static void Main(string[] args) { Console.WriteLine("My Example"); } } }
using System; /* Comment before remains */ // Comment after remains namespace ConsoleApplication1 { class Program { static void Main(string[] args) { Console.WriteLine("My Example"); } } }
برای اینکه این عمل را بتونید در کل صفحات اعمال کنید میتوانید از cleanup selected code هم استفاده کنید؛ به جز اینکه فضاهای نام اضافی را هم پاک میکند، کلیه کدهای شما را در قالبی شکیلتر و خواناتر قرار خواهد داد.
با کلیدهای Ctrl+k+d سند انتخابی و با کلیدهای ترکیبی Ctrl+k+f هم محدوده انتخاب شده قالب بندی میشود.
ویژگی سی شارپ 6 در مورد Using
فرض کنید ما یک کلاس ایستا به نام utilities ایجاد کردیم که یک متد به اسم addints دارد. حالا و این کلاس در namespace به نام SomeNamespace قرار دارد. مطمئنا در این حالت ما ابتدا فضای نام را using میکنیم و سپس در کد کلاس، متد را به شکل زیر صدا میزنیم:
using System; using SomeNamespace; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { int sum = Utility.AddInts(5, 2); Console.ReadLine(); } } }
به شکل زیر دقت کنید:
using System; using SomeNamespace.Utility; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { int sum = AddInts(5, 2); Console.ReadLine(); } } }
نکته پایانی:در visual studio 2014 فضاهای نام اضافی به رنگ خاکستری نمایش داده میشوند.
منابع:
اشتراکها